init projectmycelium
This commit is contained in:
115
src/views/auth/login.html
Normal file
115
src/views/auth/login.html
Normal file
@@ -0,0 +1,115 @@
|
||||
{% extends "base.html" %} {% block title %}Login - Project Mycelium{% endblock %} {%
|
||||
block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card mt-5">
|
||||
<div class="card-header">
|
||||
<h2 id="loginTitle">Login</h2>
|
||||
</div>
|
||||
<div class="card-body" id="loginCardBody">
|
||||
<!-- Error Messages -->
|
||||
{% if error_message %}
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong>Login Failed:</strong> {{ error_message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if not gitea_enabled %}
|
||||
<form method="post" action="/login">
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label"
|
||||
>Password</label
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password"
|
||||
name="password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Login
|
||||
</button>
|
||||
</form>
|
||||
{% else %}
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="text-center">
|
||||
<p>Or login with:</p>
|
||||
<a href="/auth/gitea" class="btn btn-secondary">
|
||||
<img
|
||||
src="/static/images/gitea-logo.svg"
|
||||
alt="Gitea"
|
||||
width="20"
|
||||
height="20"
|
||||
style="margin-right: 5px"
|
||||
/>
|
||||
Login with Gitea
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
|
||||
<hr />
|
||||
|
||||
{% if not gitea_enabled %}
|
||||
<div class="text-center">
|
||||
<p>
|
||||
Don't have an account?
|
||||
<a href="/register">Register</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Check if coming from checkout flow
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const isCheckout = urlParams.get('checkout') === 'true';
|
||||
|
||||
if (isCheckout) {
|
||||
// Update page title
|
||||
const loginTitle = document.getElementById('loginTitle');
|
||||
if (loginTitle) {
|
||||
loginTitle.innerHTML = '<i class="bi bi-cart-check me-2"></i>Login to Complete Checkout';
|
||||
}
|
||||
|
||||
// Add checkout notice
|
||||
const cardBody = document.getElementById('loginCardBody');
|
||||
if (cardBody) {
|
||||
const checkoutNotice = document.createElement('div');
|
||||
checkoutNotice.className = 'alert alert-info d-flex align-items-center mb-3';
|
||||
checkoutNotice.innerHTML = `
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<div>
|
||||
<strong>Your cart is waiting!</strong><br>
|
||||
<small>Log in to access your saved cart items and complete your purchase securely.</small>
|
||||
</div>
|
||||
`;
|
||||
cardBody.insertBefore(checkoutNotice, cardBody.firstChild);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
134
src/views/auth/register.html
Normal file
134
src/views/auth/register.html
Normal file
@@ -0,0 +1,134 @@
|
||||
{% extends "base.html" %} {% block title %}Register - Project Mycelium{% endblock %}
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card mt-5">
|
||||
<div class="card-header">
|
||||
<h2 id="registerTitle">Register</h2>
|
||||
</div>
|
||||
<div class="card-body" id="registerCardBody">
|
||||
<!-- Error Messages -->
|
||||
{% if error_message %}
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong>Registration Failed:</strong> {{ error_message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="/register">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="name"
|
||||
name="name"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label"
|
||||
>Password</label
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password"
|
||||
name="password"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label
|
||||
for="password_confirmation"
|
||||
class="form-label"
|
||||
>Confirm Password</label
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
id="password_confirmation"
|
||||
name="password_confirmation"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Register
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="text-center">
|
||||
<p>
|
||||
Already have an account? <a href="/login">Login</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Check if coming from checkout flow
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const isCheckout = urlParams.get('checkout') === 'true';
|
||||
|
||||
if (isCheckout) {
|
||||
// Update page title
|
||||
const registerTitle = document.getElementById('registerTitle');
|
||||
if (registerTitle) {
|
||||
registerTitle.innerHTML = '<i class="bi bi-cart-check me-2"></i>Create Account to Complete Checkout';
|
||||
}
|
||||
|
||||
// Add checkout notice
|
||||
const cardBody = document.getElementById('registerCardBody');
|
||||
if (cardBody) {
|
||||
const checkoutNotice = document.createElement('div');
|
||||
checkoutNotice.className = 'alert alert-success d-flex align-items-center mb-3';
|
||||
checkoutNotice.innerHTML = `
|
||||
<i class="bi bi-gift me-2"></i>
|
||||
<div>
|
||||
<strong>Welcome to ThreeFold!</strong><br>
|
||||
<small>Create your free account to access your cart and complete your purchase. It only takes 30 seconds!</small>
|
||||
</div>
|
||||
`;
|
||||
cardBody.insertBefore(checkoutNotice, cardBody.firstChild);
|
||||
}
|
||||
|
||||
// Update the login link to include checkout parameter
|
||||
const loginLink = document.querySelector('a[href="/login"]');
|
||||
if (loginLink) {
|
||||
loginLink.href = '/login?checkout=true';
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent double submission
|
||||
const registerForm = document.querySelector('form[action="/register"]');
|
||||
if (registerForm) {
|
||||
registerForm.addEventListener('submit', function() {
|
||||
const submitButton = registerForm.querySelector('button[type="submit"]');
|
||||
if (submitButton) {
|
||||
submitButton.disabled = true;
|
||||
submitButton.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> Registering...';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
204
src/views/base.html
Normal file
204
src/views/base.html
Normal file
@@ -0,0 +1,204 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Project Mycelium{% endblock %}</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/static/css/styles.css">
|
||||
<link rel="icon" href="/static/images/logo_light.png">
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" height="30" class="me-2">
|
||||
<span>Project Mycelium</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
|
||||
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto">
|
||||
<li class="nav-item d-flex align-items-center">
|
||||
<a class="nav-link {{ active_class(current=active_page, page="home") }}" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item d-flex align-items-center">
|
||||
<a class="nav-link {{ active_class(current=active_page, page="marketplace") }}"
|
||||
href="/marketplace">Marketplace</a>
|
||||
</li>
|
||||
<li class="nav-item d-flex align-items-center">
|
||||
<a class="nav-link {{ active_class(current=active_page, page="dashboard") }}"
|
||||
href="/dashboard">Dashboard</a>
|
||||
</li>
|
||||
<li class="nav-item d-flex align-items-center">
|
||||
<a class="nav-link {{ active_class(current=active_page, page="docs") }}"
|
||||
href="/docs">Docs</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav me-3">
|
||||
<li class="nav-item d-flex align-items-center" id="cartNavItem" style="display: none;">
|
||||
<a class="nav-link position-relative" href="/cart" id="cartLink">
|
||||
<i class="bi bi-cart3 me-1"></i>Cart
|
||||
<span class="position-absolute badge rounded-pill bg-danger cart-count" style="top: 2px; right: -12px; display: none;">
|
||||
0
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav">
|
||||
{% if user_json is defined and user_json %}
|
||||
<!-- OpenRouter-style user dropdown -->
|
||||
<li class="nav-item dropdown d-flex align-items-center">
|
||||
<a class="nav-link dropdown-toggle d-flex align-items-center position-relative" href="#" id="userDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="me-2">
|
||||
<i class="bi bi-person-circle fs-5"></i>
|
||||
</div>
|
||||
<div class="d-none d-md-block">
|
||||
<div class="fw-semibold" id="navbar-username">{% if user is defined and user.name %}{{ user.name }}{% elif user is defined %}{{ user.email }}{% else %}User{% endif %}</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Message notification badge -->
|
||||
<span class="position-absolute badge rounded-pill bg-danger d-none" id="navbar-message-badge" style="font-size: 0.7rem; top: 0px; right: -5px;">
|
||||
0
|
||||
</span>
|
||||
</a>
|
||||
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="userDropdown" style="min-width: 280px;">
|
||||
<li class="dropdown-header">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="fw-semibold">Wallet Balance</span>
|
||||
<span class="badge bg-primary" id="dropdown-balance">Loading...</span>
|
||||
</div>
|
||||
<div class="small text-muted mt-1">
|
||||
<span id="dropdown-currency-indicator">USD</span>
|
||||
</div>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex align-items-center" href="/dashboard/wallet">
|
||||
<i class="bi bi-wallet2 me-2 text-primary"></i>
|
||||
<span>Wallet</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex align-items-center position-relative" href="#" onclick="window.openMessaging(); return false;">
|
||||
<i class="bi bi-chat-dots me-2 text-info"></i>
|
||||
<span>Messages</span>
|
||||
<span class="position-absolute badge rounded-pill bg-danger navbar-message-badge ms-2" style="display: none; font-size: 0.6rem; top: 50%; transform: translateY(-50%); right: 8px;">0</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex align-items-center" href="/dashboard/settings">
|
||||
<i class="bi bi-gear me-2 text-secondary"></i>
|
||||
<span>Settings</span>
|
||||
</a>
|
||||
</li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li>
|
||||
<a class="dropdown-item d-flex align-items-center" href="/logout">
|
||||
<i class="bi bi-box-arrow-right me-2 text-danger"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ active_class(current=active_page, page="login") }}"
|
||||
href="/login">Login</a>
|
||||
</li>
|
||||
{% if gitea_enabled == false %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ active_class(current=active_page, page="register") }}"
|
||||
href="/register">Register</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="py-4 main-content">
|
||||
<!-- Debug info (temporarily hidden)
|
||||
{% if user_json is defined and user_json %}
|
||||
<div class="container mb-4" style="font-size: 0.8rem; color: #999;">
|
||||
<details>
|
||||
<summary>Debug Info</summary>
|
||||
<pre>user_json: {{ user_json }}</pre>
|
||||
<pre>user object exists: {{ user is defined }}</pre>
|
||||
<pre>is_gitea_flow_active: {{ gitea_enabled }}</pre>
|
||||
{% if user is defined %}
|
||||
<pre>user.name: {{ user.name }}</pre>
|
||||
{% endif %}
|
||||
</details>
|
||||
</div>
|
||||
{% endif %}
|
||||
-->
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="footer mt-auto py-5 bg-light" style="position: relative; z-index: 1030;">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-12">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-3 mb-4">
|
||||
<h5 class="text-start">Menu</h5>
|
||||
<ul class="nav flex-column text-start">
|
||||
<li class="nav-item mb-2"><a href="/" class="nav-link p-0 text-muted">Home</a></li>
|
||||
<li class="nav-item mb-2"><a href="/marketplace" class="nav-link p-0 text-muted">Marketplace</a></li>
|
||||
<li class="nav-item mb-2"><a href="/dashboard" class="nav-link p-0 text-muted">Dashboard</a></li>
|
||||
<li class="nav-item mb-2"><a href="/docs" class="nav-link p-0 text-muted">Docs</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<h5 class="text-start">Actions</h5>
|
||||
<ul class="nav flex-column text-start">
|
||||
<li class="nav-item mb-2"><a href="/register" class="nav-link p-0 text-muted">Register</a></li>
|
||||
<li class="nav-item mb-2"><a href="/login" class="nav-link p-0 text-muted">Log In</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<h5 class="text-start">Legal</h5>
|
||||
<ul class="nav flex-column text-start">
|
||||
<li class="nav-item mb-2"><a href="/privacy" class="nav-link p-0 text-muted">Privacy Policy</a></li>
|
||||
<li class="nav-item mb-2"><a href="/terms" class="nav-link p-0 text-muted">Terms and Conditions</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-3 mb-4">
|
||||
<h5 class="text-start">Resources</h5>
|
||||
<ul class="nav flex-column text-start">
|
||||
<li class="nav-item mb-2"><a href="/about" class="nav-link p-0 text-muted">About</a></li>
|
||||
<li class="nav-item mb-2"><a href="/contact" class="nav-link p-0 text-muted">Contact</a></li>
|
||||
<li class="nav-item mb-2"><a href="https://threefold.io" target="_blank" class="nav-link p-0 text-muted">ThreeFold</a></li>
|
||||
<li class="nav-item mb-2"><a href="https://github.com/threefoldtech" target="_blank" class="nav-link p-0 text-muted">TF9</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center pt-4 mt-4 border-top">
|
||||
<p class="text-muted"> 2025 Project Mycelium. All rights reserved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="/static/js/base.js"></script>
|
||||
<script src="/static/js/modal-system.js"></script>
|
||||
<script src="/static/js/utils/errors.js"></script>
|
||||
<script src="/static/js/utils/shared-handlers.js"></script>
|
||||
<script src="/static/js/notification-system.js"></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
<script src="/static/js/buy-now.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
676
src/views/cart.html
Normal file
676
src/views/cart.html
Normal file
@@ -0,0 +1,676 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Shopping Cart - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<!-- Header with login prompt -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="mb-1">
|
||||
<i class="bi bi-cart3 me-2"></i>Shopping Cart
|
||||
</h1>
|
||||
<p class="lead mb-0">Review your selected services</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="/" class="btn btn-outline-primary">
|
||||
<i class="bi bi-shop me-1"></i> Continue Shopping
|
||||
</a>
|
||||
<a href="/register" class="btn btn-primary">
|
||||
<i class="bi bi-person-plus me-1"></i> Sign Up for Better Experience
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Login Benefits Banner -->
|
||||
<div class="alert alert-info mb-4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h6 class="mb-1">
|
||||
<i class="bi bi-star me-1"></i> Get More with a Free Account
|
||||
</h6>
|
||||
<p class="mb-0">
|
||||
Track orders, save payment methods, manage deployments, and access your dashboard.
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<a href="/register?return_url=/cart" class="btn btn-success me-2">
|
||||
<i class="bi bi-person-plus me-1"></i> Create a Free Account
|
||||
</a>
|
||||
<a href="/login?return_url=/cart" class="btn btn-outline-success">
|
||||
<i class="bi bi-box-arrow-in-right me-1"></i> Login
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Content (Same as dashboard version but standalone) -->
|
||||
<div class="row">
|
||||
<!-- Cart Items -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-list-ul me-2"></i>Cart Items
|
||||
<span class="badge bg-primary ms-2" id="cartItemsCount">0</span>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body" id="cartItemsContainer">
|
||||
<!-- Cart items will be loaded here -->
|
||||
<div class="text-center py-5" id="emptyCartMessage">
|
||||
<i class="bi bi-cart-x display-1 text-muted mb-3"></i>
|
||||
<h4 class="text-muted">Your cart is empty</h4>
|
||||
<p class="text-muted mb-4">Browse our marketplace to find services for your projects</p>
|
||||
<a href="/marketplace" class="btn btn-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Summary -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-calculator me-2"></i>Order Summary
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="summary-section" id="cartSummary">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span id="cartSubtotal">$0.00</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Estimated Deploy Time:</span>
|
||||
<span id="cartDeployTime">0 minutes</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<strong>Total:</strong>
|
||||
<strong id="cartTotal">$0.00</strong>
|
||||
</div>
|
||||
|
||||
<!-- Guest Checkout Options -->
|
||||
<div class="checkout-options mb-3">
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
<strong>Sign up to complete purchase</strong><br>
|
||||
<small>Create a free account to buy USD credits and deploy services.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/register?return_url=/checkout" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-person-plus me-1"></i>
|
||||
Sign Up & Checkout
|
||||
</a>
|
||||
<a href="/login?return_url=/checkout" class="btn btn-outline-primary">
|
||||
<i class="bi bi-box-arrow-in-right me-1"></i>
|
||||
Login & Checkout
|
||||
</a>
|
||||
<button class="btn btn-outline-danger" id="clearCartBtn" disabled data-bs-toggle="modal" data-bs-target="#clearCartModal">
|
||||
<i class="bi bi-trash me-1"></i>
|
||||
Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Guest Features -->
|
||||
<div class="card shadow-sm mt-3">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-gift me-2"></i>Why Create an Account?
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li class="mb-2">
|
||||
<i class="bi bi-check-circle text-success me-2"></i>
|
||||
Track order history and deployments
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<i class="bi bi-check-circle text-success me-2"></i>
|
||||
Save payment methods securely
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<i class="bi bi-check-circle text-success me-2"></i>
|
||||
Manage services from dashboard
|
||||
</li>
|
||||
<li class="mb-2">
|
||||
<i class="bi bi-check-circle text-success me-2"></i>
|
||||
Auto top-up wallet balance
|
||||
</li>
|
||||
<li class="mb-0">
|
||||
<i class="bi bi-check-circle text-success me-2"></i>
|
||||
Access to advanced features
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Clear Cart Confirmation Modal (Marketplace UI) -->
|
||||
<div class="modal fade" id="clearCartModal" tabindex="-1" aria-labelledby="clearCartModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="clearCartModalLabel"><i class="bi bi-trash me-2"></i>Clear Cart</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
Are you sure you want to clear your cart? This action cannot be undone.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmClearCartBtn">
|
||||
<i class="bi bi-trash me-1"></i> Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Item Template (Same as dashboard version) -->
|
||||
<template id="cartItemTemplate">
|
||||
<div class="cart-item border-bottom py-3" data-item-id="">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="service-icon me-3">
|
||||
<i class="bi bi-server display-6 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-1 service-name"></h6>
|
||||
<p class="text-muted mb-0 service-specs"></p>
|
||||
<small class="text-muted added-time"></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-center">
|
||||
<div class="price-display">
|
||||
<span class="h5 mb-0 service-price"></span>
|
||||
<small class="text-muted d-block">per month</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<div class="item-actions">
|
||||
<button class="btn btn-sm btn-outline-primary me-2" data-action="cart.edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger" data-action="cart.remove">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadCartItems();
|
||||
updateCartSummary();
|
||||
|
||||
// Listen for cart updates
|
||||
window.addEventListener('cartUpdated', function() {
|
||||
loadCartItems();
|
||||
updateCartSummary();
|
||||
});
|
||||
|
||||
// Setup clear cart confirm button
|
||||
const confirmClearCartBtn = document.getElementById('confirmClearCartBtn');
|
||||
if (confirmClearCartBtn) {
|
||||
confirmClearCartBtn.addEventListener('click', clearCart);
|
||||
}
|
||||
|
||||
// Check if user should be redirected to dashboard
|
||||
checkUserRedirect();
|
||||
|
||||
// Post-reload success toast for cart clear
|
||||
try {
|
||||
if (sessionStorage.getItem('cartCleared') === '1') {
|
||||
sessionStorage.removeItem('cartCleared');
|
||||
showToast('Cart cleared', 'success');
|
||||
}
|
||||
} catch (_) { /* storage not available */ }
|
||||
});
|
||||
|
||||
function checkUserRedirect() {
|
||||
// Check if user is logged in (this would be set by the backend)
|
||||
const isLoggedIn = document.body.dataset.userLoggedIn === 'true';
|
||||
|
||||
if (isLoggedIn) {
|
||||
// Redirect to dashboard cart with a notice
|
||||
showToast('Redirecting to your dashboard...', 'info');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/dashboard/cart';
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadCartItems() {
|
||||
try {
|
||||
// Fetch cart data from server API for guest users
|
||||
const response = await window.apiJson('/api/cart', { cache: 'no-store' });
|
||||
// apiJson already handles JSON parsing
|
||||
let cartData = response || {};
|
||||
// Handle ResponseBuilder format where data is nested under 'data' field
|
||||
const actualCartData = cartData.data || cartData || {};
|
||||
const cartItems = actualCartData.items || [];
|
||||
|
||||
const container = document.getElementById('cartItemsContainer');
|
||||
const emptyMessage = document.getElementById('emptyCartMessage');
|
||||
const itemsCount = document.getElementById('cartItemsCount');
|
||||
const clearCartBtn = document.getElementById('clearCartBtn');
|
||||
|
||||
if (itemsCount) {
|
||||
itemsCount.textContent = cartItems.length;
|
||||
}
|
||||
|
||||
if (cartItems.length === 0) {
|
||||
if (emptyMessage && container) {
|
||||
emptyMessage.style.display = 'block';
|
||||
container.innerHTML = '';
|
||||
container.appendChild(emptyMessage);
|
||||
}
|
||||
if (clearCartBtn) {
|
||||
clearCartBtn.disabled = true;
|
||||
}
|
||||
// Reset summary to zero when cart is empty
|
||||
const subtotalEl = document.getElementById('cartSubtotal');
|
||||
const totalEl = document.getElementById('cartTotal');
|
||||
const deployEl = document.getElementById('cartDeployTime');
|
||||
if (subtotalEl) subtotalEl.textContent = '$0.00';
|
||||
if (totalEl) totalEl.textContent = '$0.00';
|
||||
if (deployEl) deployEl.textContent = '0 minutes';
|
||||
return;
|
||||
}
|
||||
|
||||
if (emptyMessage) {
|
||||
emptyMessage.style.display = 'none';
|
||||
}
|
||||
if (container) {
|
||||
container.innerHTML = '';
|
||||
|
||||
cartItems.forEach(item => {
|
||||
const itemElement = createCartItemElement(item);
|
||||
container.appendChild(itemElement);
|
||||
});
|
||||
}
|
||||
|
||||
if (clearCartBtn) {
|
||||
clearCartBtn.disabled = false;
|
||||
}
|
||||
|
||||
// Update cart summary with server data
|
||||
updateCartSummary(actualCartData);
|
||||
|
||||
// Update navbar cart count in real-time
|
||||
if (typeof window.updateCartCount === 'function') {
|
||||
window.updateCartCount();
|
||||
} else {
|
||||
updateNavbarCartCount();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading cart items:', error);
|
||||
// Avoid noisy toast on empty/not found; show only for real errors
|
||||
if (!(error && (String(error).includes('404') || String(error).toLowerCase().includes('no content')))) {
|
||||
showToast('Failed to load cart items', 'error');
|
||||
}
|
||||
|
||||
// Fallback to empty state
|
||||
const container = document.getElementById('cartItemsContainer');
|
||||
const emptyMessage = document.getElementById('emptyCartMessage');
|
||||
const itemsCount = document.getElementById('cartItemsCount');
|
||||
const clearCartBtn = document.getElementById('clearCartBtn');
|
||||
|
||||
if (itemsCount) {
|
||||
itemsCount.textContent = '0';
|
||||
}
|
||||
|
||||
if (emptyMessage && container) {
|
||||
emptyMessage.style.display = 'block';
|
||||
container.innerHTML = '';
|
||||
container.appendChild(emptyMessage);
|
||||
}
|
||||
|
||||
if (clearCartBtn) {
|
||||
clearCartBtn.disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createCartItemElement(item) {
|
||||
const template = document.getElementById('cartItemTemplate');
|
||||
const element = template.content.cloneNode(true);
|
||||
|
||||
const container = element.querySelector('.cart-item');
|
||||
container.setAttribute('data-item-id', item.product_id);
|
||||
|
||||
// Use correct field names from cart API response
|
||||
element.querySelector('.service-name').textContent = item.product_name || 'Unknown Service';
|
||||
element.querySelector('.service-specs').textContent = formatSpecs(item.specifications);
|
||||
element.querySelector('.service-price').textContent = item.total_price || '0.00 USD';
|
||||
|
||||
// For now, show quantity since we don't have added_at timestamp in the API
|
||||
const quantityText = item.quantity > 1 ? ` (Qty: ${item.quantity})` : '';
|
||||
element.querySelector('.added-time').textContent = `${item.provider_name || 'Provider'}${quantityText}`;
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
function formatSpecs(specs) {
|
||||
if (!specs || Object.keys(specs).length === 0) {
|
||||
return 'Standard configuration';
|
||||
}
|
||||
|
||||
// Handle different specification formats
|
||||
const specParts = [];
|
||||
|
||||
if (specs.cpu) specParts.push(`${specs.cpu} CPU`);
|
||||
if (specs.memory) specParts.push(`${specs.memory}GB RAM`);
|
||||
if (specs.storage) specParts.push(`${specs.storage}GB Storage`);
|
||||
if (specs.bandwidth) specParts.push(`${specs.bandwidth} Bandwidth`);
|
||||
|
||||
// If no standard specs, show key-value pairs
|
||||
if (specParts.length === 0) {
|
||||
for (const [key, value] of Object.entries(specs)) {
|
||||
if (value !== null && value !== undefined) {
|
||||
specParts.push(`${key}: ${value}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return specParts.length > 0 ? specParts.join(' • ') : 'Standard configuration';
|
||||
}
|
||||
|
||||
function formatTime(timestamp) {
|
||||
const date = new Date(timestamp);
|
||||
const now = new Date();
|
||||
const diff = now - date;
|
||||
const minutes = Math.floor(diff / 60000);
|
||||
|
||||
if (minutes < 1) return 'just now';
|
||||
if (minutes < 60) return `${minutes}m ago`;
|
||||
if (minutes < 1440) return `${Math.floor(minutes / 60)}h ago`;
|
||||
return date.toLocaleDateString();
|
||||
}
|
||||
|
||||
function updateCartSummary(cartData) {
|
||||
// Use server cart data if provided, otherwise fetch from localStorage as fallback
|
||||
let cartItems, subtotal, total;
|
||||
|
||||
if (cartData) {
|
||||
// Use server cart data (handle ResponseBuilder format)
|
||||
const actualCartData = cartData.data || cartData;
|
||||
cartItems = actualCartData.items || [];
|
||||
subtotal = actualCartData.subtotal || '0.00';
|
||||
total = actualCartData.total || '0.00';
|
||||
} else {
|
||||
// Fallback to localStorage (legacy) - convert to USD
|
||||
cartItems = getCartItems();
|
||||
subtotal = cartItems.reduce((sum, item) => sum + (item.price_usd || item.price_tfc || 0), 0);
|
||||
total = subtotal;
|
||||
}
|
||||
|
||||
const deployTime = cartItems.length * 2; // Estimate 2 minutes per service
|
||||
|
||||
// Always display as USD format
|
||||
const subtotalValue = typeof subtotal === 'string' ? parseFloat(subtotal.replace(/[^0-9.-]/g, '')) : subtotal;
|
||||
const totalValue = typeof total === 'string' ? parseFloat(total.replace(/[^0-9.-]/g, '')) : total;
|
||||
|
||||
document.getElementById('cartSubtotal').textContent = `$${subtotalValue.toFixed(2)}`;
|
||||
document.getElementById('cartTotal').textContent = `$${totalValue.toFixed(2)}`;
|
||||
document.getElementById('cartDeployTime').textContent = `${deployTime} minutes`;
|
||||
}
|
||||
|
||||
async function removeCartItem(button) {
|
||||
const cartItem = button.closest('.cart-item');
|
||||
const itemId = cartItem.getAttribute('data-item-id');
|
||||
|
||||
const success = await removeFromCart(itemId);
|
||||
if (success) {
|
||||
// UI is updated by loadCartItems within removeFromCart
|
||||
updateCartSummary();
|
||||
}
|
||||
}
|
||||
|
||||
function editCartItem(button) {
|
||||
showToast('Sign up to edit cart items', 'info');
|
||||
}
|
||||
|
||||
function clearCartConfirm() {
|
||||
const modal = new bootstrap.Modal(document.getElementById('clearCartModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
// Include cart management functions (same as dashboard layout)
|
||||
function getCartItems() {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem('cart_items') || '[]');
|
||||
} catch (error) {
|
||||
console.error('Error getting cart items:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update navbar cart count in real-time
|
||||
async function updateNavbarCartCount() {
|
||||
try {
|
||||
const response = await window.apiJson('/api/cart', { cache: 'no-store' });
|
||||
if (response) {
|
||||
// apiJson already handles JSON parsing
|
||||
const actualData = response.data || response || {};
|
||||
const itemCount = parseInt(actualData.item_count) || 0;
|
||||
|
||||
// Update cart count elements
|
||||
const cartCountElements = document.querySelectorAll('.cart-count, #cartItemsCount');
|
||||
cartCountElements.forEach(element => {
|
||||
if (element) {
|
||||
element.textContent = itemCount;
|
||||
}
|
||||
});
|
||||
|
||||
// Update navbar cart visibility
|
||||
const cartNavItem = document.getElementById('cartNavItem');
|
||||
if (cartNavItem) {
|
||||
if (itemCount > 0) {
|
||||
cartNavItem.style.display = 'block';
|
||||
} else {
|
||||
cartNavItem.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating navbar cart count:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function removeFromCart(itemId) {
|
||||
try {
|
||||
const response = await window.apiJson(`/api/cart/item/${itemId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
// apiJson already handles JSON parsing
|
||||
|
||||
if (response && response.success) {
|
||||
showToast('Item removed from cart', 'success');
|
||||
|
||||
// Remove the item from DOM immediately
|
||||
const cartItem = document.querySelector(`[data-item-id="${itemId}"]`);
|
||||
if (cartItem) {
|
||||
cartItem.remove();
|
||||
}
|
||||
|
||||
// Update navbar cart count with multiple methods for reliability
|
||||
|
||||
// Method 1: Direct DOM count (immediate)
|
||||
const remainingItemsAfterUpdate = document.querySelectorAll('[data-item-id]');
|
||||
const newCount = remainingItemsAfterUpdate.length;
|
||||
|
||||
const cartNavItem = document.getElementById('cartNavItem');
|
||||
const cartCountElements = document.querySelectorAll('.cart-count, #cartItemsCount');
|
||||
|
||||
// Update all cart count elements immediately
|
||||
cartCountElements.forEach(element => {
|
||||
if (element) {
|
||||
element.textContent = newCount;
|
||||
}
|
||||
});
|
||||
|
||||
// Update navbar visibility
|
||||
if (cartNavItem) {
|
||||
if (newCount > 0) {
|
||||
cartNavItem.style.display = 'block';
|
||||
} else {
|
||||
cartNavItem.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Method 2: Global function (with slight delay to ensure DOM is updated)
|
||||
setTimeout(() => {
|
||||
if (window.updateCartCount) {
|
||||
window.updateCartCount();
|
||||
}
|
||||
}, 100);
|
||||
|
||||
// Method 3: API-based update as final backup
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await updateNavbarCartCount();
|
||||
} catch (error) {
|
||||
console.error('Error updating navbar cart count:', error);
|
||||
}
|
||||
}, 200);
|
||||
|
||||
// Check if cart is now empty and update display
|
||||
const remainingItems = document.querySelectorAll('[data-item-id]');
|
||||
if (remainingItems.length === 0) {
|
||||
// Show empty cart message
|
||||
const container = document.getElementById('cartItemsContainer');
|
||||
const emptyMessage = document.getElementById('emptyCartMessage');
|
||||
if (container && emptyMessage) {
|
||||
container.innerHTML = '';
|
||||
emptyMessage.style.display = 'block';
|
||||
container.appendChild(emptyMessage);
|
||||
}
|
||||
// Disable clear cart button
|
||||
const clearCartBtn = document.getElementById('clearCartBtn');
|
||||
if (clearCartBtn) {
|
||||
clearCartBtn.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update cart items count
|
||||
const itemsCount = document.getElementById('cartItemsCount');
|
||||
if (itemsCount) {
|
||||
itemsCount.textContent = remainingItems.length;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
throw new Error(result.error || result.message || 'Failed to remove item');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error removing from cart:', error);
|
||||
showToast(`Failed to remove item: ${error.message}`, 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function clearCart() {
|
||||
// Hide modal if open
|
||||
const modalInstance = bootstrap.Modal.getInstance(document.getElementById('clearCartModal'));
|
||||
if (modalInstance) modalInstance.hide();
|
||||
try {
|
||||
const response = await window.apiJson('/api/cart', { method: 'DELETE' });
|
||||
// apiJson already handles JSON parsing and error checking
|
||||
if (!response || (response && response.success === false)) {
|
||||
const msg = (response && (response.error || response.message)) || 'Failed to clear cart';
|
||||
throw new Error(msg);
|
||||
}
|
||||
// Reload page to reflect empty cart immediately and avoid mixed toasts
|
||||
// Also update navbar count event just before reload for consistency
|
||||
if (typeof window.emitCartUpdated === 'function') { window.emitCartUpdated(0); }
|
||||
if (typeof window.updateCartCount === 'function') { window.updateCartCount(); }
|
||||
try { sessionStorage.setItem('cartCleared', '1'); } catch (_) {}
|
||||
setTimeout(() => { window.location.reload(); }, 50);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error clearing cart:', error);
|
||||
showToast('Failed to clear cart', 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Toast notification function
|
||||
function showToast(message, type = 'info') {
|
||||
// Create toast element if it doesn't exist
|
||||
let toastContainer = document.getElementById('toastContainer');
|
||||
if (!toastContainer) {
|
||||
toastContainer = document.createElement('div');
|
||||
toastContainer.id = 'toastContainer';
|
||||
toastContainer.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 9999;
|
||||
max-width: 300px;
|
||||
`;
|
||||
document.body.appendChild(toastContainer);
|
||||
}
|
||||
|
||||
// Create toast
|
||||
const toast = document.createElement('div');
|
||||
const bgColor = type === 'success' ? '#28a745' : type === 'error' ? '#dc3545' : '#007bff';
|
||||
toast.style.cssText = `
|
||||
background-color: ${bgColor};
|
||||
color: white;
|
||||
padding: 12px 16px;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
|
||||
opacity: 0;
|
||||
transform: translateX(100%);
|
||||
transition: all 0.3s ease;
|
||||
`;
|
||||
toast.textContent = message;
|
||||
|
||||
toastContainer.appendChild(toast);
|
||||
|
||||
// Animate in
|
||||
setTimeout(() => {
|
||||
toast.style.opacity = '1';
|
||||
toast.style.transform = 'translateX(0)';
|
||||
}, 100);
|
||||
|
||||
// Remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
toast.style.opacity = '0';
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.parentNode.removeChild(toast);
|
||||
}
|
||||
}, 300);
|
||||
}, 3000);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
250
src/views/changelog.html
Normal file
250
src/views/changelog.html
Normal file
@@ -0,0 +1,250 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Changelog - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-10 mx-auto">
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<i class="bi bi-clock-history me-3" style="font-size: 2rem; color: #0066cc;"></i>
|
||||
<div>
|
||||
<h1 class="mb-1">Project Mycelium Changelog</h1>
|
||||
<p class="text-muted mb-0">Latest updates and improvements to the platform</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="changelog-content">
|
||||
<!-- Version 0.0.6 - Centralized 402 Handling & Client Audits -->
|
||||
<div class="changelog-entry mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-primary me-3 px-3 py-2">v0.0.6</span>
|
||||
<h2 class="h3 mb-0">Centralized Insufficient Funds (HTTP 402) & Client Audits</h2>
|
||||
<span class="text-muted ms-auto">August 18, 2025</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-gear me-2"></i>Platform & Flows</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Global fetch interceptor for HTTP 402 in <code>src/static/js/base.js</code> with response clone + modal dedupe</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Unified modal via <code>window.Errors.handleInsufficientFundsResponse</code></li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Early-returns on 402 across add-to-cart, buy-now, and checkout to avoid duplicate UI</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Completed ResponseBuilder migration across controllers; removed direct <code>HttpResponse::</code> constructions</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-file-text me-2"></i>Docs & UX</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Roadmap updated (HTML + Markdown)</li>
|
||||
<li class="mb-2"><i class="bi bi-info-circle text-primary me-2"></i>Clarified status: Architecture refactor program ~85% overall; ResponseBuilder migration 100%</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Consistent UX: single modal; buttons reset on early return</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Version 0.0.5 - Builder Pattern & Architecture Refactor -->
|
||||
<div class="changelog-entry mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-info me-3 px-3 py-2">v0.0.5</span>
|
||||
<h2 class="h3 mb-0">Builder Pattern & Architecture Refactor</h2>
|
||||
<span class="text-muted ms-auto">August 6, 2025</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-tools me-2"></i>Builders</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>ResponseBuilder architecture across controllers</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>SessionDataBuilder for persistent user data</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>ConfigurationBuilder improvements</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-shield-check me-2"></i>Code Quality</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Reduced logs; streamlined controllers</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Improved docs and architecture guides</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Version 0.0.4 - Cart & UX Improvements -->
|
||||
<div class="changelog-entry mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-warning me-3 px-3 py-2">v0.0.4</span>
|
||||
<h2 class="h3 mb-0">Cart & UX Improvements</h2>
|
||||
<span class="text-muted ms-auto">August 5, 2025</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-cart me-2"></i>Cart</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Delete flow fixes; count resets post-purchase</li>
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Persistent cart data for new users</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-person-check me-2"></i>UX</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Improved checkout/payment flow</li>
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Better navigation for logged-out users</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Version 0.0.3 - TFP to TFC Migration -->
|
||||
<div class="changelog-entry mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-secondary me-3 px-3 py-2">v0.0.3</span>
|
||||
<h2 class="h3 mb-0">TFP → TFC Credit System Migration</h2>
|
||||
<span class="text-muted ms-auto">August 2–4, 2025</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-currency-dollar me-2"></i>Credits</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>1 TFC = 1 USD model</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Wallet displays credits</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-layout-text-window me-2"></i>Dashboard</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Updated cart layout and order management</li>
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>FAQ/About pages updated</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Version 0.0.2 - Platform Rebranding & Workflow -->
|
||||
<div class="changelog-entry mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-success me-3 px-3 py-2">v0.0.2</span>
|
||||
<h2 class="h3 mb-0">Platform Rebranding & Workflow</h2>
|
||||
<span class="text-muted ms-auto">August 2–3, 2025</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-tag me-2"></i>Rebranding</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Renamed to <code>projectmycelium</code></li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Docs and navigation refreshed</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-gear me-2"></i>Workflow</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Automated deployment workflow</li>
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Improved ops documentation</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Version 0.0.1 - Foundation -->
|
||||
<div class="changelog-entry mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-dark me-3 px-3 py-2">v0.0.1</span>
|
||||
<h2 class="h3 mb-0">Foundation</h2>
|
||||
<span class="text-muted ms-auto">July 2025</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-building me-2"></i>Core</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Initial marketplace foundation</li>
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>User authentication system</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group">
|
||||
<h4 class="h5 text-primary mb-3"><i class="bi bi-server me-2"></i>Infrastructure</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>ThreeFold Grid integration</li>
|
||||
<li class="mb-2"><i class="bi bi-plus-circle text-success me-2"></i>Basic dashboard functionality</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5 pt-4 border-top">
|
||||
<p class="text-muted">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
For technical details and development updates, see our
|
||||
<a href="/docs" class="text-decoration-none">documentation</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.changelog-entry {
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 12px;
|
||||
padding: 2rem;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.changelog-entry:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.feature-group {
|
||||
background: rgba(255,255,255,0.7);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
height: 100%;
|
||||
border: 1px solid rgba(0,102,204,0.1);
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.changelog-content .bi-check-circle-fill {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.changelog-content .bi-plus-circle {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.changelog-content h4 {
|
||||
border-bottom: 2px solid rgba(0,102,204,0.2);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
345
src/views/dashboard/app_provider.html
Normal file
345
src/views/dashboard/app_provider.html
Normal file
@@ -0,0 +1,345 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - App Provider{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>App Provider Dashboard</h1>
|
||||
<p class="lead">Develop, deploy, and manage applications for the ThreeFold ecosystem</p>
|
||||
|
||||
<!-- Status Summary -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h5 class="card-title">Published Apps</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if app_provider_data is defined and app_provider_data.published_apps is defined %}{{ app_provider_data.published_apps }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Active</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h5 class="card-title">Active Deployments</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if app_provider_data is defined and app_provider_data.active_deployments is defined %}{{ app_provider_data.active_deployments }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Instances</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h5 class="card-title">Customer Base</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if app_provider_data is defined and app_provider_data.total_deployments is defined %}{{ app_provider_data.total_deployments }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Total Deployments</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h5 class="card-title">Monthly Earnings</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if app_provider_data is defined and app_provider_data.monthly_revenue_usd is defined %}{{ app_provider_data.monthly_revenue_usd }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">$/month</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Register New App Button -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-end">
|
||||
<a href="#" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#registerAppModal">
|
||||
<i class="bi bi-plus-circle me-2"></i> Register New Application
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Published Applications Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>My Published Applications</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Application</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th>Version</th>
|
||||
<th>Active Deployments</th>
|
||||
<th>Average Rating</th>
|
||||
<th>Monthly Revenue</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="apps-list-tbody">
|
||||
<!-- Apps will be populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Application Deployments Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Active Deployments</h3>
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
Each application can have multiple deployments across different users and environments.
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Deployment ID</th>
|
||||
<th>Application</th>
|
||||
<th>Customer</th>
|
||||
<th>Region</th>
|
||||
<th>Instances</th>
|
||||
<th>Deployed On</th>
|
||||
<th>Status</th>
|
||||
<th>Health</th>
|
||||
<th>Resource Usage</th>
|
||||
<th>Revenue</th>
|
||||
<th>Monitoring</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="active-deployments-tbody">
|
||||
<!-- Active deployments will be populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center mt-3">
|
||||
<nav aria-label="Deployments pagination">
|
||||
<ul class="pagination">
|
||||
<li class="page-item disabled">
|
||||
<a class="page-link" href="#" tabindex="-1" aria-disabled="true">Previous</a>
|
||||
</li>
|
||||
<li class="page-item active"><a class="page-link" href="#">1</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">2</a></li>
|
||||
<li class="page-item"><a class="page-link" href="#">3</a></li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="#">Next</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Development Resources Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Developer Resources</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-book me-2 text-primary"></i> Documentation</h5>
|
||||
<p>Access guides, tutorials, and API references for developing ThreeFold applications</p>
|
||||
<a href="https://manual.threefold.io" target="_blank" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-box-arrow-up-right me-1"></i>Browse Documentation
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-people me-2 text-info"></i> Developer Community</h5>
|
||||
<p>Connect with other ThreeFold application developers, share insights, and get help</p>
|
||||
<a href="https://t.me/threefoldtesting" target="_blank" class="btn btn-sm btn-outline-info">
|
||||
<i class="bi bi-box-arrow-up-right me-1"></i>Join Community
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Revenue Monitoring Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Revenue Monitoring</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Monthly Revenue Trend</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="revenueChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Revenue by Application</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="revenueDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Charts Row -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Deployment Trend</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="deploymentTrendChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>App Performance</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="appPerformanceChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<!-- Hydration JSON for initial app provider dashboard data (safe, non-executable) -->
|
||||
<script id="ap-dashboard-hydration" type="application/json">
|
||||
{% if app_provider_data is defined %}
|
||||
{{ app_provider_data | json_encode() }}
|
||||
{% else %}
|
||||
null
|
||||
{% endif %}
|
||||
</script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
<script src="/static/js/dashboard-app-provider.js"></script>
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card-body {
|
||||
min-height: 340px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
<!-- Register Application Modal -->
|
||||
<div class="modal fade" id="registerAppModal" tabindex="-1" aria-labelledby="registerAppModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="registerAppModalLabel">Register New Application</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="appName" class="form-label">Application Name</label>
|
||||
<input type="text" class="form-control" id="appName" placeholder="Enter application name">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="appDesc" class="form-label">Description</label>
|
||||
<textarea class="form-control" id="appDesc" rows="3" placeholder="Describe your application"></textarea>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="appCategory" class="form-label">Category</label>
|
||||
<select class="form-select" id="appCategory">
|
||||
<option selected>Select category</option>
|
||||
<option value="productivity">Productivity</option>
|
||||
<option value="communication">Communication</option>
|
||||
<option value="business">Business</option>
|
||||
<option value="storage">Storage & Backup</option>
|
||||
<option value="development">Development Tools</option>
|
||||
<option value="analytics">Analytics & BI</option>
|
||||
<option value="other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="appType" class="form-label">Deployment Type</label>
|
||||
<select class="form-select" id="appType">
|
||||
<option selected>Select type</option>
|
||||
<option value="container">Container-based</option>
|
||||
<option value="vm">Virtual Machine</option>
|
||||
<option value="kubernetes">Kubernetes Workload</option>
|
||||
<option value="custom">Custom Deployment</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="appRepo" class="form-label">Source Repository URL</label>
|
||||
<input type="url" class="form-control" id="appRepo" placeholder="https://github.com/yourusername/yourrepo">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="resourceRequirements" class="form-label">Minimum Resource Requirements</label>
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-2">
|
||||
<input type="number" class="form-control" id="minCPU" placeholder="vCPU Cores">
|
||||
</div>
|
||||
<div class="col-md-4 mb-2">
|
||||
<input type="number" class="form-control" id="minRAM" placeholder="RAM (GB)">
|
||||
</div>
|
||||
<div class="col-md-4 mb-2">
|
||||
<input type="number" class="form-control" id="minStorage" placeholder="Storage (GB)">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="appPrice" class="form-label">Pricing Model</label>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-2">
|
||||
<select class="form-select" id="pricingType">
|
||||
<option selected>Select pricing model</option>
|
||||
<option value="subscription">Subscription (per user/month)</option>
|
||||
<option value="usage">Usage-based</option>
|
||||
<option value="fixed">Fixed price (per instance)</option>
|
||||
<option value="free">Free</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" id="priceAmount" placeholder="Amount">
|
||||
<span class="input-group-text">$</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="selfHealing">
|
||||
<label class="form-check-label" for="selfHealing">Enable self-healing capabilities</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" id="registerAppBtn">Register Application</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
208
src/views/dashboard/cart.html
Normal file
208
src/views/dashboard/cart.html
Normal file
@@ -0,0 +1,208 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}Shopping Cart - ThreeFold Dashboard{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<!-- Header with marketplace navigation -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="mb-1">
|
||||
<i class="bi bi-cart3 me-2"></i>Shopping Cart
|
||||
</h1>
|
||||
<p class="lead mb-0">Review and manage your selected services</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="/" class="btn btn-outline-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
<a href="/orders" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-receipt me-1"></i> Order History
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Content -->
|
||||
<div class="row">
|
||||
<!-- Cart Items -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-list-ul me-2"></i>Cart Items
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body" id="cartItemsContainer">
|
||||
<!-- Cart items will be loaded here -->
|
||||
<div class="text-center py-5" id="emptyCartMessage">
|
||||
<i class="bi bi-cart-x display-1 text-muted mb-3"></i>
|
||||
<h4 class="text-muted">Your cart is empty</h4>
|
||||
<p class="text-muted mb-4">Browse our marketplace to find services for your projects</p>
|
||||
<a href="/marketplace" class="btn btn-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Summary -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-calculator me-2"></i>Order Summary
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="summary-section" id="cartSummary">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span id="cartSubtotal">{{ currency_symbol | default(value="$") }}0.00</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Estimated Deploy Time:</span>
|
||||
<span id="cartDeployTime">0 minutes</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<strong>Total:</strong>
|
||||
<strong id="cartTotal">{{ currency_symbol | default(value="$") }}0.00</strong>
|
||||
</div>
|
||||
|
||||
<!-- Wallet Balance Check -->
|
||||
<div class="wallet-status mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span>Your {{ display_currency | default(value="USD") }} Credits:</span>
|
||||
<span class="fw-bold" id="userBalance">{{ currency_symbol | default(value="$") }}0.00</span>
|
||||
</div>
|
||||
<div class="balance-indicator mt-2" id="balanceIndicator">
|
||||
<!-- Balance status will be shown here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary btn-lg" id="checkoutBtn" data-action="proceed-checkout" disabled>
|
||||
<i class="bi bi-credit-card me-1"></i>
|
||||
Proceed to Checkout
|
||||
</button>
|
||||
<button class="btn btn-outline-danger" id="clearCartBtn" disabled data-bs-toggle="modal" data-bs-target="#clearCartModal">
|
||||
<i class="bi bi-trash me-1"></i>
|
||||
Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="card shadow-sm mt-3">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-lightning me-2"></i>Quick Actions
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/dashboard/wallet" class="btn btn-outline-success btn-sm">
|
||||
<i class="bi bi-wallet2 me-1"></i>
|
||||
Top Up Wallet
|
||||
</a>
|
||||
<button class="btn btn-outline-info btn-sm" data-action="save-for-later">
|
||||
<i class="bi bi-bookmark me-1"></i>
|
||||
Save for Later
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary btn-sm" data-action="share-cart">
|
||||
<i class="bi bi-share me-1"></i>
|
||||
Share Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Item Template -->
|
||||
<template id="cartItemTemplate">
|
||||
<div class="cart-item border-bottom py-3" data-item-id="">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="service-icon me-3">
|
||||
<i class="bi bi-server display-6 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="mb-1 service-name"></h6>
|
||||
<p class="text-muted mb-0 service-specs"></p>
|
||||
<small class="text-muted added-time"></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-center">
|
||||
<div class="price-display">
|
||||
<span class="h5 mb-0 service-price"></span>
|
||||
<small class="text-muted d-block">per month</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<div class="item-actions d-flex align-items-center">
|
||||
<!-- Quantity Controls -->
|
||||
<div class="quantity-controls d-flex align-items-center me-3">
|
||||
<button class="btn btn-sm btn-outline-secondary" data-action="decrease-qty" title="Decrease quantity">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
<span class="quantity-display mx-2 fw-bold" style="min-width: 30px; text-align: center;">1</span>
|
||||
<button class="btn btn-sm btn-outline-secondary" data-action="increase-qty" title="Increase quantity">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Remove Button -->
|
||||
<button class="btn btn-sm btn-outline-danger" data-action="remove-item" title="Remove item">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Clear Cart Confirmation Modal (Dashboard) -->
|
||||
<div class="modal fade" id="clearCartModal" tabindex="-1" aria-labelledby="clearCartModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="clearCartModalLabel"><i class="bi bi-trash me-2"></i>Clear Cart</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
Are you sure you want to clear your cart? This action cannot be undone.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmClearCartBtn" data-action="confirm-clear-cart">
|
||||
<i class="bi bi-trash me-1"></i> Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block hydration %}
|
||||
{{ super() }}
|
||||
<script id="hydration-dashboard-cart" type="application/json">
|
||||
{
|
||||
"currency_symbol": {{ currency_symbol | default(value="$") | json_encode() }},
|
||||
"display_currency": {{ display_currency | default(value="USD") | json_encode() }}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="/static/js/dashboard_cart.js"></script>
|
||||
{% endblock %}
|
||||
1153
src/views/dashboard/farmer.html
Normal file
1153
src/views/dashboard/farmer.html
Normal file
File diff suppressed because it is too large
Load Diff
305
src/views/dashboard/index.html
Normal file
305
src/views/dashboard/index.html
Normal file
@@ -0,0 +1,305 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Overview{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="mb-1">Dashboard Overview</h1>
|
||||
<p class="lead mb-0">Welcome, {% if user.name %}{{ user.name }}{% else %}{{ user.email }}{% endif %}</p>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<a href="/dashboard/wallet" class="btn btn-primary">
|
||||
<i class="bi bi-currency-exchange me-1"></i> Get Credits
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status Summary -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h5 class="card-title">Active Deployments</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{% if user_metrics is defined and user_metrics.active_deployments_count is defined %}{{ user_metrics.active_deployments_count }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Applications</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h5 class="card-title">Resources</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ active_compute_resources_count | default(value=0) }}</h2>
|
||||
<small class="text-muted">Active Slices</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h5 class="card-title">Current Cost</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ total_monthly_cost | default(value=0) | format_decimal(precision=2) }}</h2>
|
||||
<small class="text-muted">{{ currency_symbol | default(value="$") }}/month</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h5 class="card-title">Wallet Balance</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0" id="dashboardWalletBalance">{{ currency_symbol | default(value="$") }}{% if user_metrics is defined and user_metrics.wallet_balance is defined %}{{ user_metrics.wallet_balance | format_decimal(precision=2) }}{% else %}0{% endif %}</h2>
|
||||
<small class="text-muted">Credits (<span id="dashboardCurrencyCode">{{ display_currency | default(value="USD") }}</span>)</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Quick Actions</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<a href="/marketplace/applications" class="btn btn-outline-primary w-100 mb-2">
|
||||
<i class="bi bi-box-seam me-2"></i> Deploy Applications
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/marketplace/compute" class="btn btn-outline-success w-100 mb-2">
|
||||
<i class="bi bi-cpu me-2"></i> Reserve Resources
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/dashboard/wallet" class="btn btn-outline-info w-100 mb-2">
|
||||
<i class="bi bi-wallet2 me-2"></i> Manage Wallet
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/dashboard/farmer" class="btn btn-outline-info w-100 mb-2">
|
||||
<i class="bi bi-hdd-rack me-2"></i> Add a 3Node
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<a href="/dashboard/settings" class="btn btn-outline-secondary w-100 mb-2">
|
||||
<i class="bi bi-gear me-2"></i> Account Settings
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<a href="/marketplace" class="btn btn-outline-dark w-100 mb-2">
|
||||
<i class="bi bi-shop me-2"></i> Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Roles Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<h3>Your Roles</h3>
|
||||
<p>Manage your ThreeFold experience through different perspectives:</p>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-primary badge-role">USER</span>
|
||||
<h4>User Dashboard</h4>
|
||||
<p>Deploy apps, manage resources, monitor costs, and track usage.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/user" class="btn btn-sm btn-outline-primary">Access User Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-success badge-role">FARMER</span>
|
||||
<h4>Farmer Dashboard</h4>
|
||||
<p>Manage your nodes, create slices, set pricing, and track earnings.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/farmer" class="btn btn-sm btn-outline-success">Access Farmer Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-info badge-role">APP PROVIDER</span>
|
||||
<h4>App Provider Dashboard</h4>
|
||||
<p>Develop, deploy, and manage applications for the TF ecosystem.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/app-provider" class="btn btn-sm btn-outline-info">Access App Provider Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3 mb-4">
|
||||
<div class="dashboard-card">
|
||||
<span class="badge bg-warning badge-role">SERVICE PROVIDER</span>
|
||||
<h4>Service Provider Dashboard</h4>
|
||||
<p>Offer professional services and manage maintenance requests.</p>
|
||||
<div class="d-grid">
|
||||
<a href="/dashboard/service-provider" class="btn btn-sm btn-outline-warning">Access Service Provider Dashboard</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistics Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Statistics</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Resource Utilization</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="resourceUtilizationOverviewChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Credits Usage Trend</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="creditsUsageOverviewChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>User Activity</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="userActivityChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Deployment Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="deploymentDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Recent Activity</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Action</th>
|
||||
<th>Status</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% if recent_activities is defined and recent_activities and recent_activities | length > 0 %}
|
||||
{% for activity in recent_activities %}
|
||||
<tr>
|
||||
<td>{{ activity.date }}</td>
|
||||
<td>{{ activity.action }}</td>
|
||||
<td>
|
||||
{% if activity.status == "Completed" %}
|
||||
<span class="badge bg-success">{{ activity.status }}</span>
|
||||
{% elif activity.status == "Active" %}
|
||||
<span class="badge bg-success">{{ activity.status }}</span>
|
||||
{% elif activity.status == "Pending" %}
|
||||
<span class="badge bg-info">{{ activity.status }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ activity.status }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ activity.details }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-center text-muted">No recent activity</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card.h-100 {
|
||||
height: 400px !important;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
height: 340px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- JSON hydration for dashboard charts -->
|
||||
<script type="application/json" id="dashboard-chart-data">
|
||||
{
|
||||
"displayCurrency": "{% if display_currency is defined and display_currency %}{{ display_currency }}{% else %}USD{% endif %}",
|
||||
"resourceUtilization": {
|
||||
{% if user_metrics is defined and user_metrics.resource_utilization is defined %}
|
||||
"cpu": {{ user_metrics.resource_utilization.cpu }},
|
||||
"memory": {{ user_metrics.resource_utilization.memory }},
|
||||
"storage": {{ user_metrics.resource_utilization.storage }},
|
||||
"network": {{ user_metrics.resource_utilization.network }}
|
||||
{% else %}
|
||||
"cpu": 0, "memory": 0, "storage": 0, "network": 0
|
||||
{% endif %}
|
||||
},
|
||||
"creditsUsageTrend": [
|
||||
{% if user_metrics is defined and user_metrics.cost_trend is defined %}
|
||||
{% for value in user_metrics.cost_trend %}{{ value }}{% if not loop.last %}, {% endif %}{% endfor %}
|
||||
{% else %}0, 0, 0, 0, 0, 0{% endif %}
|
||||
],
|
||||
"userActivity": {
|
||||
"deployments": [
|
||||
0, 0, 0, 0, 0, 0
|
||||
],
|
||||
"resourceReservations": [
|
||||
0, 0, 0, 0, 0, 0
|
||||
]
|
||||
},
|
||||
"deploymentDistribution": {
|
||||
"regions": [],
|
||||
"nodes": [],
|
||||
"slices": [],
|
||||
"apps": [],
|
||||
"gateways": []
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Externalized dashboard logic (charts + wallet updater) -->
|
||||
<script src="/static/js/dashboard.js"></script>
|
||||
{% endblock %}
|
||||
238
src/views/dashboard/layout.html
Normal file
238
src/views/dashboard/layout.html
Normal file
@@ -0,0 +1,238 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar Toggle Button (mobile only) -->
|
||||
<button class="btn sidebar-toggle d-md-none" id="sidebarToggleBtn" aria-label="Toggle sidebar navigation" aria-expanded="false" aria-controls="sidebar">
|
||||
<i class="bi bi-list"></i> Menu
|
||||
</button>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse" id="sidebar">
|
||||
<div class="position-sticky pt-3">
|
||||
<h5 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mb-1 text-muted">
|
||||
<span>Dashboard</span>
|
||||
</h5>
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'home' %}active{% endif %}" href="/dashboard">
|
||||
<i class="bi bi-speedometer2 me-1"></i>
|
||||
Overview
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'user' %}active{% endif %}" href="/dashboard/user">
|
||||
<i class="bi bi-person me-1"></i>
|
||||
User
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'farmer' %}active{% endif %}" href="/dashboard/farmer">
|
||||
<i class="bi bi-hdd-rack me-1"></i>
|
||||
Farmer
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'app_provider' %}active{% endif %}" href="/dashboard/app-provider">
|
||||
<i class="bi bi-app me-1"></i>
|
||||
App Provider
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'service_provider' %}active{% endif %}" href="/dashboard/service-provider">
|
||||
<i class="bi bi-person-workspace me-1"></i>
|
||||
Service Provider
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'wallet' %}active{% endif %}" href="/dashboard/wallet">
|
||||
<i class="bi bi-wallet2 me-1"></i>
|
||||
Wallet
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Shopping & Orders Section -->
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||
<span>Shopping</span>
|
||||
</h6>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'cart' %}active{% endif %}" href="/dashboard/cart" id="cartNavLink">
|
||||
<i class="bi bi-cart3 me-1"></i>
|
||||
Shopping Cart
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'orders' %}active{% endif %}" href="/dashboard/orders">
|
||||
<i class="bi bi-receipt me-1"></i>
|
||||
Order History
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- HIDE: Pools navigation - keeping for future use
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'pools' %}active{% endif %}" href="/dashboard/pools">
|
||||
<i class="bi bi-currency-exchange me-1"></i>
|
||||
Credits Pools
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
|
||||
<!-- Communication Section -->
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||
<span>Communication</span>
|
||||
</h6>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link position-relative {% if active_section == 'messages' %}active{% endif %}" href="/dashboard/messages">
|
||||
<i class="bi bi-chat-dots me-1"></i>
|
||||
Messages
|
||||
<span class="badge bg-danger rounded-pill ms-auto message-badge" style="display: none; font-size: 0.7rem;">0</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<!-- Settings Section -->
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
|
||||
<span>Account</span>
|
||||
</h6>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'settings' %}active{% endif %}" href="/dashboard/settings">
|
||||
<i class="bi bi-gear me-1"></i>
|
||||
Settings
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content-wrapper position-relative">
|
||||
<!-- Sidebar Backdrop (mobile only) - positioned here so it doesn't cover the sidebar -->
|
||||
<div class="sidebar-backdrop d-md-none" id="sidebarBackdrop"></div>
|
||||
{% block dashboard_content %}
|
||||
<!-- Content will be injected here by child templates -->
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<!-- Add Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css">
|
||||
|
||||
<style>
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 56px; /* Navbar height */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
padding: 20px 0 0;
|
||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||
height: 100%; /* Full height */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Footer should only appear on the right side */
|
||||
@media (min-width: 768px) {
|
||||
.footer {
|
||||
margin-left: 25%; /* Matches the width of col-md-3 */
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.footer {
|
||||
margin-left: 16.666667%; /* Matches the width of col-lg-2 */
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-heading {
|
||||
font-size: .75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
color: #2470dc;
|
||||
}
|
||||
|
||||
.dashboard-section {
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
background-color: #f8f9fa;
|
||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
|
||||
}
|
||||
|
||||
.dashboard-card {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
background-color: white;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.dashboard-card:hover {
|
||||
box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
border-left: 4px solid;
|
||||
background-color: white;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
|
||||
}
|
||||
|
||||
.stats-card.primary {
|
||||
border-left-color: #007bff;
|
||||
}
|
||||
|
||||
.stats-card.success {
|
||||
border-left-color: #28a745;
|
||||
}
|
||||
|
||||
.stats-card.info {
|
||||
border-left-color: #17a2b8;
|
||||
}
|
||||
|
||||
.stats-card.warning {
|
||||
border-left-color: #ffc107;
|
||||
}
|
||||
|
||||
.badge-role {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Adjust for fixed navbar */
|
||||
main.py-4 {
|
||||
padding-top: 4.5rem !important;
|
||||
}
|
||||
|
||||
/* Removed conflicting media query */
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="/static/js/dashboard_layout.js"></script>
|
||||
<script src="/static/js/messaging-system.js"></script>
|
||||
<script>
|
||||
// Dynamic user detection for messaging system
|
||||
try {
|
||||
// Initialize messaging system with dynamic user detection
|
||||
if (window.MessagingSystem) {
|
||||
window.MessagingSystem.initializeWithDynamicUser();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize messaging system:', error);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
136
src/views/dashboard/messages.html
Normal file
136
src/views/dashboard/messages.html
Normal file
@@ -0,0 +1,136 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">
|
||||
<i class="bi bi-chat-dots me-2"></i>Messages
|
||||
</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group me-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="refreshMessagesBtn">
|
||||
<i class="bi bi-arrow-clockwise"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Messages Interface -->
|
||||
<div class="row h-100">
|
||||
<!-- Conversations List -->
|
||||
<div class="col-md-4 col-lg-3">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-list-ul me-1"></i>Conversations
|
||||
</h6>
|
||||
<span class="badge bg-primary" id="totalConversationsCount">0</span>
|
||||
</div>
|
||||
<div class="card-body p-0" style="height: calc(100vh - 280px); min-height: 500px;">
|
||||
<div id="conversationsList" class="list-group list-group-flush h-100" style="overflow-y: auto;">
|
||||
<!-- Loading state -->
|
||||
<div class="d-flex justify-content-center align-items-center h-100" id="conversationsLoading">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary mb-3" role="status">
|
||||
<span class="visually-hidden">Loading conversations...</span>
|
||||
</div>
|
||||
<p class="text-muted">Loading conversations...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty state -->
|
||||
<div class="d-flex justify-content-center align-items-center h-100 d-none" id="conversationsEmpty">
|
||||
<div class="text-center text-muted">
|
||||
<i class="bi bi-chat-square-text fs-1 mb-3"></i>
|
||||
<h6>No conversations yet</h6>
|
||||
<p class="small">Start a conversation from the marketplace or user profiles</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message View -->
|
||||
<div class="col-md-8 col-lg-9 d-flex flex-column" style="height: calc(100vh - 200px);">
|
||||
<div class="card h-100 d-flex flex-column">
|
||||
<!-- Message Header -->
|
||||
<div class="card-header d-none flex-shrink-0" id="messageHeader">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-0" id="conversationTitle">Select a conversation</h6>
|
||||
<small class="text-muted" id="conversationParticipants"></small>
|
||||
</div>
|
||||
<div>
|
||||
<span class="badge bg-secondary" id="conversationContext">general</span>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary ms-2" id="markAsReadBtn">
|
||||
<i class="bi bi-check2-all"></i> Mark as Read
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Welcome/Empty State -->
|
||||
<div class="card-body d-flex justify-content-center align-items-center flex-grow-1" id="messagesWelcome" style="background: #f8f9fa;">
|
||||
<div class="text-center text-muted">
|
||||
<i class="bi bi-chat-square-dots fs-1 mb-3"></i>
|
||||
<h5>Welcome to Messages</h5>
|
||||
<p>Select a conversation from the left to view messages</p>
|
||||
<p class="small">You can start conversations from marketplace listings or user profiles</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Messages Area -->
|
||||
<div class="card-body flex-grow-1 p-3 d-none overflow-auto" id="messagesContainer" style="background: linear-gradient(to bottom, #fafafa 0%, #ffffff 100%);">
|
||||
<!-- Messages will be populated here -->
|
||||
</div>
|
||||
|
||||
<!-- Message Input -->
|
||||
<div class="card-footer border-top p-3 flex-shrink-0 d-none" id="messageInputContainer" style="background: white;">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="messageInput" placeholder="Type your message..." maxlength="1000" disabled>
|
||||
<button class="btn btn-primary" type="button" id="sendMessageBtn" disabled>
|
||||
<i class="bi bi-send"></i>
|
||||
</button>
|
||||
</div>
|
||||
<small class="text-muted mt-1 d-block">Press Enter to send • <span id="messageCharCount">0</span>/1000 characters</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container -->
|
||||
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 1055;">
|
||||
<div id="successToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-success text-white">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
<strong class="me-auto">Success</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="successToastBody">
|
||||
Message sent successfully!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="errorToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-danger text-white">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong class="me-auto">Error</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="errorToastBody">
|
||||
An error occurred!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="application/json" id="messages-hydration">
|
||||
{
|
||||
"user_email": {{ user_email | default(value="") | json_encode() | safe }}
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/dashboard-messages.js"></script>
|
||||
{% endblock %}
|
||||
201
src/views/dashboard/orders.html
Normal file
201
src/views/dashboard/orders.html
Normal file
@@ -0,0 +1,201 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}Order History - ThreeFold Dashboard{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<!-- Header with marketplace navigation -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="mb-1">
|
||||
<i class="bi bi-receipt me-2"></i>Order History
|
||||
</h1>
|
||||
<p class="lead mb-0">Track your purchases and deployments</p>
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<a href="/" class="btn btn-outline-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
<a href="/dashboard/cart" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-cart3 me-1"></i> Shopping Cart
|
||||
<span class="badge bg-primary ms-1" id="cartBadge" style="display: none;">0</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Orders Filter and Search -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-4">
|
||||
<label for="orderStatus" class="form-label">Filter by Status</label>
|
||||
<select class="form-select" id="orderStatus">
|
||||
<option value="">All Orders</option>
|
||||
<option value="pending">Pending</option>
|
||||
<option value="processing">Processing</option>
|
||||
<option value="deployed">Deployed</option>
|
||||
<option value="active">Active</option>
|
||||
<option value="failed">Failed</option>
|
||||
<option value="cancelled">Cancelled</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="orderPeriod" class="form-label">Time Period</label>
|
||||
<select class="form-select" id="orderPeriod">
|
||||
<option value="">All Time</option>
|
||||
<option value="7">Last 7 days</option>
|
||||
<option value="30">Last 30 days</option>
|
||||
<option value="90">Last 3 months</option>
|
||||
<option value="365">Last year</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="orderSearch" class="form-label">Search Orders</label>
|
||||
<input type="text" class="form-control" id="orderSearch" placeholder="Order ID or service name...">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="mb-1" id="totalOrders">0</h5>
|
||||
<small class="text-muted">Total Orders</small>
|
||||
<hr class="my-2">
|
||||
<h6 class="mb-1 text-success" id="totalSpent">0</h6>
|
||||
<small class="text-muted">Total Spent</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Orders List -->
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-list-ul me-2"></i>Your Orders
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body" id="ordersContainer">
|
||||
<!-- Orders will be loaded here -->
|
||||
<div class="text-center py-5" id="noOrdersMessage">
|
||||
<i class="bi bi-receipt display-1 text-muted mb-3"></i>
|
||||
<h4 class="text-muted">No orders found</h4>
|
||||
<p class="text-muted mb-4">Start shopping to see your order history here</p>
|
||||
<a href="/" class="btn btn-primary">
|
||||
<i class="bi bi-shop me-1"></i> Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Item Template -->
|
||||
<template id="orderItemTemplate">
|
||||
<div class="order-item border-bottom py-3" data-order-id="">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="order-icon me-3">
|
||||
<i class="bi bi-box-seam display-6 text-primary"></i>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
<h6 class="mb-1">
|
||||
<span class="order-id"></span>
|
||||
<span class="badge order-status ms-2"></span>
|
||||
</h6>
|
||||
<p class="text-muted mb-1 order-services"></p>
|
||||
<small class="text-muted order-date"></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-center">
|
||||
<div class="price-display">
|
||||
<span class="h6 mb-0 order-total"></span>
|
||||
<small class="text-muted d-block">Total Cost</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-end">
|
||||
<div class="order-actions">
|
||||
<button class="btn btn-sm btn-outline-primary me-2" data-action="toggle-details">
|
||||
<i class="bi bi-eye"></i> Details
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-three-dots"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#" data-action="view-invoice">
|
||||
<i class="bi bi-eye me-1"></i> View Invoice
|
||||
</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-action="contact-support">
|
||||
<i class="bi bi-headset me-1"></i> Contact Support
|
||||
</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Expandable Order Details -->
|
||||
<div class="order-details mt-3" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h6>Services Ordered:</h6>
|
||||
<div class="order-services-list">
|
||||
<!-- Services will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<h6>Deployment Status:</h6>
|
||||
<div class="deployment-status">
|
||||
<!-- Deployment info will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Order Details Modal -->
|
||||
<div class="modal fade" id="orderDetailsModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">
|
||||
<i class="bi bi-receipt me-2"></i>Order Details
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="orderDetailsContent">
|
||||
<!-- Order details will be loaded here -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" data-action="view-invoice-from-modal">
|
||||
<i class="bi bi-eye me-1"></i> View Invoice
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="application/json" id="orders-hydration">
|
||||
{
|
||||
"currency_symbol": {{ currency_symbol | default(value='$') | json_encode() }},
|
||||
"display_currency": {{ display_currency | default(value='USD') | json_encode() }}
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/dashboard_orders.js"></script>
|
||||
{% endblock %}
|
||||
621
src/views/dashboard/pools.html
Normal file
621
src/views/dashboard/pools.html
Normal file
@@ -0,0 +1,621 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Credits Pools{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>Credits Pools</h1>
|
||||
<p class="lead">Exchange currencies and tokens through ThreeFold liquidity pools</p>
|
||||
|
||||
|
||||
<!-- Liquidity Pools Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Available Liquidity Pools</h3>
|
||||
<p>Exchange between different currencies and tokens through our liquidity pools</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100" data-pool-id="credits-fiat">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Credits - Fiat Pool</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">Purchase Credits with fiat currencies (USD, EUR, etc.) at the fixed rate of 1 USD per Credit.</p>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Exchange rate:</span>
|
||||
<span class="fw-bold exchange-rate">1 USD = 0.85 EUR</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Pool liquidity:</span>
|
||||
<span class="fw-bold liquidity">125,000 USD</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Min transaction:</span>
|
||||
<span class="fw-bold">$10</span>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#buyCreditsModal">Buy Credits</button>
|
||||
<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#sellCreditsModal">Sell Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100" data-pool-id="credits-tft">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0">Credits - TFT Pool</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">Exchange between USD Credits and ThreeFold Tokens (TFT).</p>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Current rate:</span>
|
||||
<span class="fw-bold exchange-rate">1 USD ≈ 5 TFT</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Pool liquidity:</span>
|
||||
<span class="fw-bold liquidity">25,000 USD / 125,000 TFT</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Min transaction:</span>
|
||||
<span class="fw-bold">$10 / 50 TFT</span>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#buyCreditsWithTFTModal">Buy Credits</button>
|
||||
<button class="btn btn-outline-success" data-bs-toggle="modal" data-bs-target="#sellCreditsForTFTModal">Sell Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100" data-pool-id="credits-peaq">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0">Credits - PEAQ Pool</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="card-text">Exchange between USD Credits and PEAQ tokens for the Peaq Network.</p>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Current rate:</span>
|
||||
<span class="fw-bold exchange-rate">1 USD ≈ 20 PEAQ</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Pool liquidity:</span>
|
||||
<span class="fw-bold liquidity">10,000 USD / 200,000 PEAQ</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<span class="text-muted">Min transaction:</span>
|
||||
<span class="fw-bold">$10 / 200 PEAQ</span>
|
||||
</div>
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-info" data-bs-toggle="modal" data-bs-target="#buyCreditsWithPEAQModal">Buy Credits</button>
|
||||
<button class="btn btn-outline-info" data-bs-toggle="modal" data-bs-target="#sellCreditsForPEAQModal">Sell Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Staking Section -->
|
||||
<div class="row mt-4" id="staking">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Credits Staking</h3>
|
||||
<p>Stake your Credits to earn discounts and increase your reputation in the ThreeFold ecosystem</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Your Staking Status</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6 class="text-muted">Currently Staked</h6>
|
||||
<h3 class="mb-0">$25</h3>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6 class="text-muted">Lock Period</h6>
|
||||
<h3 class="mb-0">3 months</h3>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6 class="text-muted">Discount Level</h6>
|
||||
<h3 class="mb-0">5%</h3>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6 class="text-muted">Reputation Bonus</h6>
|
||||
<h3 class="mb-0">+25 points</h3>
|
||||
</div>
|
||||
<div class="col-12 mt-2">
|
||||
<div class="d-grid">
|
||||
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#stakeCreditsModal">
|
||||
<i class="bi bi-plus-circle me-2"></i> Stake Credits
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Staking Benefits</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Staked Amount</th>
|
||||
<th>Discount</th>
|
||||
<th>Reputation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>$10-50</td>
|
||||
<td>5%</td>
|
||||
<td>+25 points</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$51-100</td>
|
||||
<td>10%</td>
|
||||
<td>+50 points</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$101-500</td>
|
||||
<td>15%</td>
|
||||
<td>+100 points</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>$501+</td>
|
||||
<td>20%</td>
|
||||
<td>+200 points</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Analytics Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Credits Analytics</h3>
|
||||
<p>Key metrics and historical data for Credits pools and exchanges</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Credits Exchange History</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="creditsPriceHistoryChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Liquidity Pool Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="liquidityPoolDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Exchange Volume (Last 30 Days)</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="exchangeVolumeChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Staking Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="stakingDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy TFC Credits Modal -->
|
||||
<div class="modal fade" id="buyCreditsModal" tabindex="-1" aria-labelledby="buyCreditsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="buyCreditsModalLabel">Buy USD Credits</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="creditsAmount" class="form-label">Amount of Credits to purchase</label>
|
||||
<input type="number" class="form-control" id="creditsAmount" min="10" value="100">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="paymentCurrency" class="form-label">Payment Currency</label>
|
||||
<select class="form-select" id="paymentCurrency">
|
||||
<option value="USD" selected>USD</option>
|
||||
<option value="EUR">EUR</option>
|
||||
<option value="GBP">GBP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="paymentMethod" class="form-label">Payment Method</label>
|
||||
<select class="form-select" id="paymentMethod">
|
||||
<option value="card" selected>Credit/Debit Card</option>
|
||||
<option value="bank">Bank Transfer</option>
|
||||
<option value="crypto">Cryptocurrency</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 Credit = $1.00
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">$100</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Cost:</span>
|
||||
<span class="text-end">10.00 USD</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="confirm-buy-credits-fiat">Confirm Purchase</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sell TFC Credits Modal -->
|
||||
<div class="modal fade" id="sellCreditsModal" tabindex="-1" aria-labelledby="sellCreditsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="sellCreditsModalLabel">Sell USD Credits</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="sellCreditsAmount" class="form-label">Amount of Credits to sell</label>
|
||||
<input type="number" class="form-control" id="sellCreditsAmount" min="10" max="125" value="100">
|
||||
<div class="form-text">Maximum available: $125</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="receiveCurrency" class="form-label">Receive Currency</label>
|
||||
<select class="form-select" id="receiveCurrency">
|
||||
<option value="USD" selected>USD</option>
|
||||
<option value="EUR">EUR</option>
|
||||
<option value="GBP">GBP</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="payoutMethod" class="form-label">Payout Method</label>
|
||||
<select class="form-select" id="payoutMethod">
|
||||
<option value="bank" selected>Bank Transfer</option>
|
||||
<option value="card">Card Refund</option>
|
||||
<option value="crypto">Cryptocurrency</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 Credit = $1.00
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">$100</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>You receive:</span>
|
||||
<span class="text-end">10.00 USD</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="confirm-sell-credits-fiat">Confirm Sale</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stake TFC Credits Modal -->
|
||||
<div class="modal fade" id="stakeCreditsModal" tabindex="-1" aria-labelledby="stakeCreditsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5 class="modal-title" id="stakeCreditsModalLabel">Stake USD Credits</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="stakeAmount" class="form-label">Amount to stake</label>
|
||||
<input type="number" class="form-control" id="stakeAmount" min="100" max="1000" value="500">
|
||||
<div class="form-text">Available balance: $100</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="stakeDuration" class="form-label">Lock period</label>
|
||||
<select class="form-select" id="stakeDuration">
|
||||
<option value="1">1 Month</option>
|
||||
<option value="3" selected>3 Months</option>
|
||||
<option value="6">6 Months</option>
|
||||
<option value="12">12 Months</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="alert alert-success">
|
||||
<div class="d-flex">
|
||||
<i class="bi bi-check-circle me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Staking Benefits:</strong>
|
||||
<ul class="mb-0 ps-3">
|
||||
<li>10% discount on all marketplace purchases</li>
|
||||
<li>+50 reputation points</li>
|
||||
<li>Priority access to new resources</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-action="confirm-stake-credits">Confirm Staking</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy TFC Credits with TFT Modal -->
|
||||
<div class="modal fade" id="buyTFCWithTFTModal" tabindex="-1" aria-labelledby="buyTFCWithTFTModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5 class="modal-title" id="buyTFCWithTFTModalLabel">Buy ThreeFold Credits (TFC) with TFT</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="tfcAmountTFT" class="form-label">Amount of TFC Credits to purchase</label>
|
||||
<input type="number" class="form-control" id="tfpAmountTFT" min="10" value="100">
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 TFC = 0.5 TFT
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">100 TFC</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Cost:</span>
|
||||
<span class="text-end">50 TFT</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-action="confirm-buy-tfc-tft">Confirm Purchase</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sell TFC Credits for TFT Modal -->
|
||||
<div class="modal fade" id="sellTFCForTFTModal" tabindex="-1" aria-labelledby="sellTFCForTFTModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-success text-white">
|
||||
<h5 class="modal-title" id="sellTFCForTFTModalLabel">Sell ThreeFold Credits (TFC) for TFT</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="sellTfcAmountTFT" class="form-label">Amount of TFC Credits to sell</label>
|
||||
<input type="number" class="form-control" id="sellTfpAmountTFT" min="10" max="1250" value="100">
|
||||
<div class="form-text">Maximum available: 1,250 TFC</div>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 TFC = 0.5 TFT
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">100 TFC</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>You receive:</span>
|
||||
<span class="text-end">50 TFT</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-success" data-action="confirm-sell-tfc-tft">Confirm Sale</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy TFC Credits with PEAQ Modal -->
|
||||
<div class="modal fade" id="buyTFCWithPEAQModal" tabindex="-1" aria-labelledby="buyTFCWithPEAQModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-info text-white">
|
||||
<h5 class="modal-title" id="buyTFCWithPEAQModalLabel">Buy ThreeFold Credits (TFC) with PEAQ</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="tfcAmountPEAQ" class="form-label">Amount of TFC Credits to purchase</label>
|
||||
<input type="number" class="form-control" id="tfpAmountPEAQ" min="10" value="100">
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 TFC = 2 PEAQ
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">100 TFC</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Cost:</span>
|
||||
<span class="text-end">200 PEAQ</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" data-action="confirm-buy-tfc-peaq">Confirm Purchase</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sell TFC Credits for PEAQ Modal -->
|
||||
<div class="modal fade" id="sellTFCForPEAQModal" tabindex="-1" aria-labelledby="sellTFCForPEAQModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-info text-white">
|
||||
<h5 class="modal-title" id="sellTFCForPEAQModalLabel">Sell ThreeFold Credits (TFC) for PEAQ</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="mb-3">
|
||||
<label for="sellTfcAmountPEAQ" class="form-label">Amount of TFC Credits to sell</label>
|
||||
<input type="number" class="form-control" id="sellTfpAmountPEAQ" min="10" max="1250" value="100">
|
||||
<div class="form-text">Maximum available: 1,250 TFC</div>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle-fill me-2 fs-4"></i>
|
||||
<div>
|
||||
<strong>Exchange Rate:</strong> 1 TFC = 2 PEAQ
|
||||
<hr class="my-2">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Amount:</span>
|
||||
<span class="text-end">100 TFC</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>You receive:</span>
|
||||
<span class="text-end">200 PEAQ</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-info" data-action="confirm-sell-tfc-peaq">Confirm Sale</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container for Success Messages -->
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
<div id="successToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-success text-white">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
<strong class="me-auto">Success</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="successToastBody">
|
||||
Operation completed successfully!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="errorToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-danger text-white">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong class="me-auto">Error</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="errorToastBody">
|
||||
An error occurred!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card.h-100 {
|
||||
height: 400px !important;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
height: 340px;
|
||||
}
|
||||
</style>
|
||||
<script type="application/json" id="pools-hydration">
|
||||
{
|
||||
"charts": true
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/dashboard_pools.js"></script>
|
||||
{% endblock %}
|
||||
1089
src/views/dashboard/service_provider.html
Normal file
1089
src/views/dashboard/service_provider.html
Normal file
File diff suppressed because it is too large
Load Diff
333
src/views/dashboard/service_request_invoice.html
Normal file
333
src/views/dashboard/service_request_invoice.html
Normal file
@@ -0,0 +1,333 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Service Invoice - ThreeFold Dashboard</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.invoice-header {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
border: 2px solid #2196f3;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.invoice-details {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.invoice-number {
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
color: #2196f3;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: #2196f3;
|
||||
}
|
||||
|
||||
.invoice-table th {
|
||||
background-color: #f8f9fa;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.no-print {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.card, .invoice-details {
|
||||
box-shadow: none !important;
|
||||
border: 1px solid #dee2e6 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark no-print">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>ThreeFold Dashboard</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/dashboard">
|
||||
<i class="bi bi-speedometer2 me-1"></i>Dashboard
|
||||
</a>
|
||||
<a class="nav-link active" href="/dashboard/service-provider">
|
||||
<i class="bi bi-person-workspace me-1"></i>Service Provider
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4 no-print">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/dashboard" class="text-decoration-none">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="/dashboard/service-provider" class="text-decoration-none">Service Provider</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Service Invoice</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if request %}
|
||||
<!-- Invoice Header -->
|
||||
<div class="invoice-header p-4 mb-4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h1 class="h2 mb-2">
|
||||
<i class="bi bi-receipt me-2"></i>THREEFOLD GRID SERVICE INVOICE
|
||||
</h1>
|
||||
<div class="invoice-number">INV-{{ request.id }}</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<div class="mb-2">
|
||||
<strong>Invoice Date:</strong> {{ invoice_date }}
|
||||
</div>
|
||||
<div>
|
||||
<strong>Due Date:</strong> {{ due_date }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Invoice Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="invoice-details p-4 mb-4">
|
||||
<!-- Service Provider and Bill To -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">SERVICE PROVIDER:</h6>
|
||||
<div class="fw-bold">{{ user.email }}</div>
|
||||
{% if user.name %}
|
||||
<div>{{ user.name }}</div>
|
||||
{% endif %}
|
||||
{% if user.country %}
|
||||
<div>{{ user.country }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">BILL TO:</h6>
|
||||
<div class="fw-bold">{{ request.client_name }}</div>
|
||||
{% if request.client_email %}
|
||||
<div>{{ request.client_email }}</div>
|
||||
{% endif %}
|
||||
{% if request.client_phone %}
|
||||
<div>{{ request.client_phone }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Details -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-2">SERVICE DETAILS:</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-2">
|
||||
<strong>Request ID:</strong> {{ request.id }}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<strong>Service Type:</strong> {{ request.service_name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-2">
|
||||
<strong>Service Date:</strong> {{ request.requested_date }}
|
||||
</div>
|
||||
{% if request.completed_date %}
|
||||
<div class="mb-2">
|
||||
<strong>Completion Date:</strong> {{ request.completed_date }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Billing Breakdown -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-3">BILLING BREAKDOWN:</h6>
|
||||
<table class="table invoice-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Description</th>
|
||||
<th class="text-center">Hours Worked</th>
|
||||
<th class="text-center">Rate</th>
|
||||
<th class="text-end">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ request.service_name }}</td>
|
||||
<td class="text-center">{{ request.estimated_hours }} hours</td>
|
||||
<td class="text-center">${{ rate }} per hour</td>
|
||||
<td class="text-end">${{ request.budget }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Total Amount -->
|
||||
<div class="border-top pt-4 mt-4">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-3">PAYMENT TERMS:</h6>
|
||||
<p class="mb-2">Payment is due within 30 days of invoice date.</p>
|
||||
<p class="mb-2">Please reference invoice number <strong>INV-{{ request.id }}</strong> with payment.</p>
|
||||
<p class="mb-0"><em>Thank you for choosing ThreeFold Grid services!</em></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span>${{ request.budget }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Platform fee:</span>
|
||||
<span class="text-muted">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="fw-bold fs-5">TOTAL AMOUNT:</span>
|
||||
<span class="total-amount">${{ request.budget }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Generated Date -->
|
||||
<div class="border-top pt-3 mt-4">
|
||||
<small class="text-muted">Generated on: {{ generated_date }}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Sidebar -->
|
||||
<div class="col-lg-4 no-print">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-gear me-2"></i>Invoice Actions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/dashboard/service-provider" class="btn btn-primary">
|
||||
<i class="bi bi-arrow-left me-2"></i>Back to Dashboard
|
||||
</a>
|
||||
<button class="btn btn-success js-print">
|
||||
<i class="bi bi-printer me-2"></i>Print Invoice
|
||||
</button>
|
||||
<a href="/api/dashboard/service-requests/{{ request.id }}/report" class="btn btn-outline-primary">
|
||||
<i class="bi bi-file-earmark-text me-2"></i>View Report
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6 class="mb-3">Need Help?</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/docs" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-book me-1"></i>Documentation
|
||||
</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-success" target="_blank">
|
||||
<i class="bi bi-chat-dots me-1"></i>Live Chat
|
||||
</a>
|
||||
<a href="mailto:support@threefold.io" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-envelope me-1"></i>Email Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Invoice Summary -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-info-circle me-2"></i>Invoice Summary
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Service Hours:</span>
|
||||
<span>{{ request.estimated_hours }}h</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Hourly Rate:</span>
|
||||
<span>${{ rate }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Priority:</span>
|
||||
<span class="badge bg-{% if request.priority == 'High' %}danger{% elif request.priority == 'Medium' %}warning{% else %}secondary{% endif %}">{{ request.priority }}</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="fw-bold">Total:</span>
|
||||
<span class="fw-bold text-primary">${{ request.budget }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-exclamation-triangle fs-1 text-warning mb-3"></i>
|
||||
<h3>Service Request Not Found</h3>
|
||||
<p class="text-muted">The requested service request could not be found.</p>
|
||||
<a href="/dashboard/service-provider" class="btn btn-primary">Back to Dashboard</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script type="application/json" id="service-invoice-data">{}</script>
|
||||
<script src="/static/js/print-utils.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
388
src/views/dashboard/service_request_report.html
Normal file
388
src/views/dashboard/service_request_report.html
Normal file
@@ -0,0 +1,388 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Service Request Report - ThreeFold Dashboard</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.report-header {
|
||||
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
|
||||
border: 2px solid #4caf50;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.report-details {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.status-in-progress {
|
||||
background: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border: 1px solid #bee5eb;
|
||||
}
|
||||
|
||||
.status-open {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
border: 1px solid #ffeaa7;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.progress-circle {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.progress-0-25 { background: #dc3545; }
|
||||
.progress-26-50 { background: #fd7e14; }
|
||||
.progress-51-75 { background: #ffc107; color: #000; }
|
||||
.progress-76-100 { background: #198754; }
|
||||
|
||||
@media print {
|
||||
.no-print {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.card, .report-details {
|
||||
box-shadow: none !important;
|
||||
border: 1px solid #dee2e6 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark no-print">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>ThreeFold Dashboard</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/dashboard">
|
||||
<i class="bi bi-speedometer2 me-1"></i>Dashboard
|
||||
</a>
|
||||
<a class="nav-link active" href="/dashboard/service-provider">
|
||||
<i class="bi bi-person-workspace me-1"></i>Service Provider
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4 no-print">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/dashboard" class="text-decoration-none">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="/dashboard/service-provider" class="text-decoration-none">Service Provider</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Service Report</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if request %}
|
||||
<!-- Report Header -->
|
||||
<div class="report-header p-4 mb-4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h1 class="h2 mb-2">
|
||||
<i class="bi bi-file-earmark-text me-2"></i>Service Request Report
|
||||
</h1>
|
||||
<p class="mb-0 text-muted">
|
||||
<i class="bi bi-hash me-1"></i>Request ID: {{ request.id }}
|
||||
</p>
|
||||
{% if request.completed_date %}
|
||||
<p class="mb-0 text-muted">
|
||||
<i class="bi bi-calendar me-1"></i>Completed on {{ request.completed_date }}
|
||||
</p>
|
||||
{% else %}
|
||||
<p class="mb-0 text-muted">
|
||||
<i class="bi bi-calendar me-1"></i>Completed recently
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<span class="status-badge status-{{ status_class }}">
|
||||
<i class="bi bi-check-circle me-1"></i>{{ request.status }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Report Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="report-details p-4 mb-4">
|
||||
<h3 class="mb-4">
|
||||
<i class="bi bi-info-circle me-2"></i>Service Details
|
||||
</h3>
|
||||
|
||||
<!-- Client Information -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">CLIENT INFORMATION</h6>
|
||||
<div class="mb-2">
|
||||
<strong>Name:</strong> {{ request.client_name }}
|
||||
</div>
|
||||
{% if request.client_email %}
|
||||
<div class="mb-2">
|
||||
<strong>Email:</strong> {{ request.client_email }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="mb-2">
|
||||
<strong>Email:</strong> <span class="text-muted">Not provided</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if request.client_phone %}
|
||||
<div class="mb-2">
|
||||
<strong>Phone:</strong> {{ request.client_phone }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">SERVICE INFORMATION</h6>
|
||||
<div class="mb-2">
|
||||
<strong>Service:</strong> {{ request.service_name }}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<strong>Requested Date:</strong> {{ request.requested_date }}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<strong>Estimated Hours:</strong> {{ request.estimated_hours }} hours
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Description -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-2">SERVICE DESCRIPTION</h6>
|
||||
<div class="p-3 bg-light rounded">
|
||||
{% if request.description %}
|
||||
{{ request.description }}
|
||||
{% else %}
|
||||
<span class="text-muted">{{ request.service_name }} service for {{ request.client_name }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progress Information -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-2">COMPLETION STATUS</h6>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="progress-circle
|
||||
{% if request.progress <= 25 %}progress-0-25
|
||||
{% elif request.progress <= 50 %}progress-26-50
|
||||
{% elif request.progress <= 75 %}progress-51-75
|
||||
{% else %}progress-76-100{% endif %} me-3">
|
||||
{{ request.progress }}%
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">{{ request.progress }}% Complete</div>
|
||||
<small class="text-muted">Service completion progress</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Financial Summary -->
|
||||
<div class="border-top pt-4 mt-4">
|
||||
<h6 class="text-muted mb-3">FINANCIAL SUMMARY</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Service Rate:</strong>
|
||||
<div>${{ rate }} per hour</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Hours Worked:</strong>
|
||||
<div>{{ request.estimated_hours }} hours</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span>${{ request.budget }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Platform fee:</span>
|
||||
<span class="text-muted">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="fw-bold fs-5">Total Amount:</span>
|
||||
<span class="fw-bold text-success fs-4">${{ request.budget }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Sidebar -->
|
||||
<div class="col-lg-4 no-print">
|
||||
<div class="card">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-gear me-2"></i>Report Actions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/dashboard/service-provider" class="btn btn-primary">
|
||||
<i class="bi bi-arrow-left me-2"></i>Back to Dashboard
|
||||
</a>
|
||||
<button class="btn btn-success js-print">
|
||||
<i class="bi bi-printer me-2"></i>Print Report
|
||||
</button>
|
||||
<a href="/api/dashboard/service-requests/{{ request.id }}/invoice" class="btn btn-outline-primary">
|
||||
<i class="bi bi-receipt me-2"></i>View Invoice
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6 class="mb-3">Need Help?</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/docs" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-book me-1"></i>Documentation
|
||||
</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-success" target="_blank">
|
||||
<i class="bi bi-chat-dots me-1"></i>Live Chat
|
||||
</a>
|
||||
<a href="mailto:support@threefold.io" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-envelope me-1"></i>Email Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Timeline -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-clock-history me-2"></i>Service Timeline
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="timeline">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-check-circle-fill text-success fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Request Submitted</div>
|
||||
<small class="text-muted">
|
||||
{% if request.created_date %}
|
||||
{{ request.created_date }}
|
||||
{% else %}
|
||||
{{ request.requested_date }}
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-check-circle-fill text-success fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Service Started</div>
|
||||
<small class="text-muted">{{ request.requested_date }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% if request.status == "Completed" %}
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-check-circle-fill text-success fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Service Completed</div>
|
||||
<small class="text-muted">
|
||||
{% if request.completed_date %}
|
||||
{{ request.completed_date }}
|
||||
{% else %}
|
||||
Recently completed
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-exclamation-triangle fs-1 text-warning mb-3"></i>
|
||||
<h3>Service Request Not Found</h3>
|
||||
<p class="text-muted">The requested service request could not be found.</p>
|
||||
<a href="/dashboard/service-provider" class="btn btn-primary">Back to Dashboard</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script type="application/json" id="service-report-data">{}</script>
|
||||
<script src="/static/js/print-utils.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
670
src/views/dashboard/settings.html
Normal file
670
src/views/dashboard/settings.html
Normal file
@@ -0,0 +1,670 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Settings{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>Account Settings</h1>
|
||||
<p class="lead">Manage your ThreeFold account preferences and security settings</p>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-md-3">
|
||||
<div class="nav flex-column nav-pills me-3" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||
<button class="nav-link active" id="v-pills-profile-tab" data-bs-toggle="pill" data-bs-target="#v-pills-profile" type="button" role="tab" aria-controls="v-pills-profile" aria-selected="true">Profile Information</button>
|
||||
<button class="nav-link" id="v-pills-password-tab" data-bs-toggle="pill" data-bs-target="#v-pills-password" type="button" role="tab" aria-controls="v-pills-password" aria-selected="false">Password</button>
|
||||
<button class="nav-link" id="v-pills-ssh-keys-tab" data-bs-toggle="pill" data-bs-target="#v-pills-ssh-keys" type="button" role="tab" aria-controls="v-pills-ssh-keys" aria-selected="false">SSH Keys</button>
|
||||
<button class="nav-link" id="v-pills-currency-tab" data-bs-toggle="pill" data-bs-target="#v-pills-currency" type="button" role="tab" aria-controls="v-pills-currency" aria-selected="false">Currency Preferences</button>
|
||||
<button class="nav-link" id="v-pills-delete-tab" data-bs-toggle="pill" data-bs-target="#v-pills-delete" type="button" role="tab" aria-controls="v-pills-delete" aria-selected="false">Delete Account</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<div class="tab-content" id="v-pills-tabContent">
|
||||
<!-- Profile Information -->
|
||||
<div class="tab-pane fade show active" id="v-pills-profile" role="tabpanel" aria-labelledby="v-pills-profile-tab">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Profile Information</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="profileForm">
|
||||
<div class="row mb-3">
|
||||
<label for="name" class="col-sm-3 col-form-label">Name</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="name" name="name" value="{{ user.name | default(value='') }}" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="email" class="col-sm-3 col-form-label">Email</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="email" class="form-control" id="email" value="{{ user.email }}" readonly>
|
||||
<small class="text-muted">Email address cannot be changed</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="country" class="col-sm-3 col-form-label">Country</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-select" id="country" name="country">
|
||||
<option value="">Choose country...</option>
|
||||
<option value="Afghanistan" {% if user.country == "Afghanistan" %}selected{% endif %}>Afghanistan</option>
|
||||
<option value="Albania" {% if user.country == "Albania" %}selected{% endif %}>Albania</option>
|
||||
<option value="Algeria" {% if user.country == "Algeria" %}selected{% endif %}>Algeria</option>
|
||||
<option value="Andorra" {% if user.country == "Andorra" %}selected{% endif %}>Andorra</option>
|
||||
<option value="Angola" {% if user.country == "Angola" %}selected{% endif %}>Angola</option>
|
||||
<option value="Antigua and Barbuda" {% if user.country == "Antigua and Barbuda" %}selected{% endif %}>Antigua and Barbuda</option>
|
||||
<option value="Argentina" {% if user.country == "Argentina" %}selected{% endif %}>Argentina</option>
|
||||
<option value="Armenia" {% if user.country == "Armenia" %}selected{% endif %}>Armenia</option>
|
||||
<option value="Australia" {% if user.country == "Australia" %}selected{% endif %}>Australia</option>
|
||||
<option value="Austria" {% if user.country == "Austria" %}selected{% endif %}>Austria</option>
|
||||
<option value="Azerbaijan" {% if user.country == "Azerbaijan" %}selected{% endif %}>Azerbaijan</option>
|
||||
<option value="Bahamas" {% if user.country == "Bahamas" %}selected{% endif %}>Bahamas</option>
|
||||
<option value="Bahrain" {% if user.country == "Bahrain" %}selected{% endif %}>Bahrain</option>
|
||||
<option value="Bangladesh" {% if user.country == "Bangladesh" %}selected{% endif %}>Bangladesh</option>
|
||||
<option value="Barbados" {% if user.country == "Barbados" %}selected{% endif %}>Barbados</option>
|
||||
<option value="Belarus" {% if user.country == "Belarus" %}selected{% endif %}>Belarus</option>
|
||||
<option value="Belgium" {% if user.country == "Belgium" %}selected{% endif %}>Belgium</option>
|
||||
<option value="Belize" {% if user.country == "Belize" %}selected{% endif %}>Belize</option>
|
||||
<option value="Benin" {% if user.country == "Benin" %}selected{% endif %}>Benin</option>
|
||||
<option value="Bhutan" {% if user.country == "Bhutan" %}selected{% endif %}>Bhutan</option>
|
||||
<option value="Bolivia" {% if user.country == "Bolivia" %}selected{% endif %}>Bolivia</option>
|
||||
<option value="Bosnia and Herzegovina" {% if user.country == "Bosnia and Herzegovina" %}selected{% endif %}>Bosnia and Herzegovina</option>
|
||||
<option value="Botswana" {% if user.country == "Botswana" %}selected{% endif %}>Botswana</option>
|
||||
<option value="Brazil" {% if user.country == "Brazil" %}selected{% endif %}>Brazil</option>
|
||||
<option value="Brunei" {% if user.country == "Brunei" %}selected{% endif %}>Brunei</option>
|
||||
<option value="Bulgaria" {% if user.country == "Bulgaria" %}selected{% endif %}>Bulgaria</option>
|
||||
<option value="Burkina Faso" {% if user.country == "Burkina Faso" %}selected{% endif %}>Burkina Faso</option>
|
||||
<option value="Burundi" {% if user.country == "Burundi" %}selected{% endif %}>Burundi</option>
|
||||
<option value="Cabo Verde" {% if user.country == "Cabo Verde" %}selected{% endif %}>Cabo Verde</option>
|
||||
<option value="Cambodia" {% if user.country == "Cambodia" %}selected{% endif %}>Cambodia</option>
|
||||
<option value="Cameroon" {% if user.country == "Cameroon" %}selected{% endif %}>Cameroon</option>
|
||||
<option value="Canada" {% if user.country == "Canada" %}selected{% endif %}>Canada</option>
|
||||
<option value="Central African Republic" {% if user.country == "Central African Republic" %}selected{% endif %}>Central African Republic</option>
|
||||
<option value="Chad" {% if user.country == "Chad" %}selected{% endif %}>Chad</option>
|
||||
<option value="Chile" {% if user.country == "Chile" %}selected{% endif %}>Chile</option>
|
||||
<option value="China" {% if user.country == "China" %}selected{% endif %}>China</option>
|
||||
<option value="Colombia" {% if user.country == "Colombia" %}selected{% endif %}>Colombia</option>
|
||||
<option value="Comoros" {% if user.country == "Comoros" %}selected{% endif %}>Comoros</option>
|
||||
<option value="Congo" {% if user.country == "Congo" %}selected{% endif %}>Congo</option>
|
||||
<option value="Costa Rica" {% if user.country == "Costa Rica" %}selected{% endif %}>Costa Rica</option>
|
||||
<option value="Croatia" {% if user.country == "Croatia" %}selected{% endif %}>Croatia</option>
|
||||
<option value="Cuba" {% if user.country == "Cuba" %}selected{% endif %}>Cuba</option>
|
||||
<option value="Cyprus" {% if user.country == "Cyprus" %}selected{% endif %}>Cyprus</option>
|
||||
<option value="Czech Republic" {% if user.country == "Czech Republic" %}selected{% endif %}>Czech Republic</option>
|
||||
<option value="Democratic Republic of the Congo" {% if user.country == "Democratic Republic of the Congo" %}selected{% endif %}>Democratic Republic of the Congo</option>
|
||||
<option value="Denmark" {% if user.country == "Denmark" %}selected{% endif %}>Denmark</option>
|
||||
<option value="Djibouti" {% if user.country == "Djibouti" %}selected{% endif %}>Djibouti</option>
|
||||
<option value="Dominica" {% if user.country == "Dominica" %}selected{% endif %}>Dominica</option>
|
||||
<option value="Dominican Republic" {% if user.country == "Dominican Republic" %}selected{% endif %}>Dominican Republic</option>
|
||||
<option value="Ecuador" {% if user.country == "Ecuador" %}selected{% endif %}>Ecuador</option>
|
||||
<option value="Egypt" {% if user.country == "Egypt" %}selected{% endif %}>Egypt</option>
|
||||
<option value="El Salvador" {% if user.country == "El Salvador" %}selected{% endif %}>El Salvador</option>
|
||||
<option value="Equatorial Guinea" {% if user.country == "Equatorial Guinea" %}selected{% endif %}>Equatorial Guinea</option>
|
||||
<option value="Eritrea" {% if user.country == "Eritrea" %}selected{% endif %}>Eritrea</option>
|
||||
<option value="Estonia" {% if user.country == "Estonia" %}selected{% endif %}>Estonia</option>
|
||||
<option value="Eswatini" {% if user.country == "Eswatini" %}selected{% endif %}>Eswatini</option>
|
||||
<option value="Ethiopia" {% if user.country == "Ethiopia" %}selected{% endif %}>Ethiopia</option>
|
||||
<option value="Fiji" {% if user.country == "Fiji" %}selected{% endif %}>Fiji</option>
|
||||
<option value="Finland" {% if user.country == "Finland" %}selected{% endif %}>Finland</option>
|
||||
<option value="France" {% if user.country == "France" %}selected{% endif %}>France</option>
|
||||
<option value="Gabon" {% if user.country == "Gabon" %}selected{% endif %}>Gabon</option>
|
||||
<option value="Gambia" {% if user.country == "Gambia" %}selected{% endif %}>Gambia</option>
|
||||
<option value="Georgia" {% if user.country == "Georgia" %}selected{% endif %}>Georgia</option>
|
||||
<option value="Germany" {% if user.country == "Germany" %}selected{% endif %}>Germany</option>
|
||||
<option value="Ghana" {% if user.country == "Ghana" %}selected{% endif %}>Ghana</option>
|
||||
<option value="Greece" {% if user.country == "Greece" %}selected{% endif %}>Greece</option>
|
||||
<option value="Grenada" {% if user.country == "Grenada" %}selected{% endif %}>Grenada</option>
|
||||
<option value="Guatemala" {% if user.country == "Guatemala" %}selected{% endif %}>Guatemala</option>
|
||||
<option value="Guinea" {% if user.country == "Guinea" %}selected{% endif %}>Guinea</option>
|
||||
<option value="Guinea-Bissau" {% if user.country == "Guinea-Bissau" %}selected{% endif %}>Guinea-Bissau</option>
|
||||
<option value="Guyana" {% if user.country == "Guyana" %}selected{% endif %}>Guyana</option>
|
||||
<option value="Haiti" {% if user.country == "Haiti" %}selected{% endif %}>Haiti</option>
|
||||
<option value="Honduras" {% if user.country == "Honduras" %}selected{% endif %}>Honduras</option>
|
||||
<option value="Hungary" {% if user.country == "Hungary" %}selected{% endif %}>Hungary</option>
|
||||
<option value="Iceland" {% if user.country == "Iceland" %}selected{% endif %}>Iceland</option>
|
||||
<option value="India" {% if user.country == "India" %}selected{% endif %}>India</option>
|
||||
<option value="Indonesia" {% if user.country == "Indonesia" %}selected{% endif %}>Indonesia</option>
|
||||
<option value="Iran" {% if user.country == "Iran" %}selected{% endif %}>Iran</option>
|
||||
<option value="Iraq" {% if user.country == "Iraq" %}selected{% endif %}>Iraq</option>
|
||||
<option value="Ireland" {% if user.country == "Ireland" %}selected{% endif %}>Ireland</option>
|
||||
<option value="Israel" {% if user.country == "Israel" %}selected{% endif %}>Israel</option>
|
||||
<option value="Italy" {% if user.country == "Italy" %}selected{% endif %}>Italy</option>
|
||||
<option value="Ivory Coast" {% if user.country == "Ivory Coast" %}selected{% endif %}>Ivory Coast</option>
|
||||
<option value="Jamaica" {% if user.country == "Jamaica" %}selected{% endif %}>Jamaica</option>
|
||||
<option value="Japan" {% if user.country == "Japan" %}selected{% endif %}>Japan</option>
|
||||
<option value="Jordan" {% if user.country == "Jordan" %}selected{% endif %}>Jordan</option>
|
||||
<option value="Kazakhstan" {% if user.country == "Kazakhstan" %}selected{% endif %}>Kazakhstan</option>
|
||||
<option value="Kenya" {% if user.country == "Kenya" %}selected{% endif %}>Kenya</option>
|
||||
<option value="Kiribati" {% if user.country == "Kiribati" %}selected{% endif %}>Kiribati</option>
|
||||
<option value="Kuwait" {% if user.country == "Kuwait" %}selected{% endif %}>Kuwait</option>
|
||||
<option value="Kyrgyzstan" {% if user.country == "Kyrgyzstan" %}selected{% endif %}>Kyrgyzstan</option>
|
||||
<option value="Laos" {% if user.country == "Laos" %}selected{% endif %}>Laos</option>
|
||||
<option value="Latvia" {% if user.country == "Latvia" %}selected{% endif %}>Latvia</option>
|
||||
<option value="Lebanon" {% if user.country == "Lebanon" %}selected{% endif %}>Lebanon</option>
|
||||
<option value="Lesotho" {% if user.country == "Lesotho" %}selected{% endif %}>Lesotho</option>
|
||||
<option value="Liberia" {% if user.country == "Liberia" %}selected{% endif %}>Liberia</option>
|
||||
<option value="Libya" {% if user.country == "Libya" %}selected{% endif %}>Libya</option>
|
||||
<option value="Liechtenstein" {% if user.country == "Liechtenstein" %}selected{% endif %}>Liechtenstein</option>
|
||||
<option value="Lithuania" {% if user.country == "Lithuania" %}selected{% endif %}>Lithuania</option>
|
||||
<option value="Luxembourg" {% if user.country == "Luxembourg" %}selected{% endif %}>Luxembourg</option>
|
||||
<option value="Madagascar" {% if user.country == "Madagascar" %}selected{% endif %}>Madagascar</option>
|
||||
<option value="Malawi" {% if user.country == "Malawi" %}selected{% endif %}>Malawi</option>
|
||||
<option value="Malaysia" {% if user.country == "Malaysia" %}selected{% endif %}>Malaysia</option>
|
||||
<option value="Maldives" {% if user.country == "Maldives" %}selected{% endif %}>Maldives</option>
|
||||
<option value="Mali" {% if user.country == "Mali" %}selected{% endif %}>Mali</option>
|
||||
<option value="Malta" {% if user.country == "Malta" %}selected{% endif %}>Malta</option>
|
||||
<option value="Marshall Islands" {% if user.country == "Marshall Islands" %}selected{% endif %}>Marshall Islands</option>
|
||||
<option value="Mauritania" {% if user.country == "Mauritania" %}selected{% endif %}>Mauritania</option>
|
||||
<option value="Mauritius" {% if user.country == "Mauritius" %}selected{% endif %}>Mauritius</option>
|
||||
<option value="Mexico" {% if user.country == "Mexico" %}selected{% endif %}>Mexico</option>
|
||||
<option value="Micronesia" {% if user.country == "Micronesia" %}selected{% endif %}>Micronesia</option>
|
||||
<option value="Moldova" {% if user.country == "Moldova" %}selected{% endif %}>Moldova</option>
|
||||
<option value="Monaco" {% if user.country == "Monaco" %}selected{% endif %}>Monaco</option>
|
||||
<option value="Mongolia" {% if user.country == "Mongolia" %}selected{% endif %}>Mongolia</option>
|
||||
<option value="Montenegro" {% if user.country == "Montenegro" %}selected{% endif %}>Montenegro</option>
|
||||
<option value="Morocco" {% if user.country == "Morocco" %}selected{% endif %}>Morocco</option>
|
||||
<option value="Mozambique" {% if user.country == "Mozambique" %}selected{% endif %}>Mozambique</option>
|
||||
<option value="Myanmar" {% if user.country == "Myanmar" %}selected{% endif %}>Myanmar</option>
|
||||
<option value="Namibia" {% if user.country == "Namibia" %}selected{% endif %}>Namibia</option>
|
||||
<option value="Nauru" {% if user.country == "Nauru" %}selected{% endif %}>Nauru</option>
|
||||
<option value="Nepal" {% if user.country == "Nepal" %}selected{% endif %}>Nepal</option>
|
||||
<option value="Netherlands" {% if user.country == "Netherlands" %}selected{% endif %}>Netherlands</option>
|
||||
<option value="New Zealand" {% if user.country == "New Zealand" %}selected{% endif %}>New Zealand</option>
|
||||
<option value="Nicaragua" {% if user.country == "Nicaragua" %}selected{% endif %}>Nicaragua</option>
|
||||
<option value="Niger" {% if user.country == "Niger" %}selected{% endif %}>Niger</option>
|
||||
<option value="Nigeria" {% if user.country == "Nigeria" %}selected{% endif %}>Nigeria</option>
|
||||
<option value="North Korea" {% if user.country == "North Korea" %}selected{% endif %}>North Korea</option>
|
||||
<option value="North Macedonia" {% if user.country == "North Macedonia" %}selected{% endif %}>North Macedonia</option>
|
||||
<option value="Norway" {% if user.country == "Norway" %}selected{% endif %}>Norway</option>
|
||||
<option value="Oman" {% if user.country == "Oman" %}selected{% endif %}>Oman</option>
|
||||
<option value="Pakistan" {% if user.country == "Pakistan" %}selected{% endif %}>Pakistan</option>
|
||||
<option value="Palau" {% if user.country == "Palau" %}selected{% endif %}>Palau</option>
|
||||
<option value="Palestine" {% if user.country == "Palestine" %}selected{% endif %}>Palestine</option>
|
||||
<option value="Panama" {% if user.country == "Panama" %}selected{% endif %}>Panama</option>
|
||||
<option value="Papua New Guinea" {% if user.country == "Papua New Guinea" %}selected{% endif %}>Papua New Guinea</option>
|
||||
<option value="Paraguay" {% if user.country == "Paraguay" %}selected{% endif %}>Paraguay</option>
|
||||
<option value="Peru" {% if user.country == "Peru" %}selected{% endif %}>Peru</option>
|
||||
<option value="Philippines" {% if user.country == "Philippines" %}selected{% endif %}>Philippines</option>
|
||||
<option value="Poland" {% if user.country == "Poland" %}selected{% endif %}>Poland</option>
|
||||
<option value="Portugal" {% if user.country == "Portugal" %}selected{% endif %}>Portugal</option>
|
||||
<option value="Qatar" {% if user.country == "Qatar" %}selected{% endif %}>Qatar</option>
|
||||
<option value="Romania" {% if user.country == "Romania" %}selected{% endif %}>Romania</option>
|
||||
<option value="Russia" {% if user.country == "Russia" %}selected{% endif %}>Russia</option>
|
||||
<option value="Rwanda" {% if user.country == "Rwanda" %}selected{% endif %}>Rwanda</option>
|
||||
<option value="Saint Kitts and Nevis" {% if user.country == "Saint Kitts and Nevis" %}selected{% endif %}>Saint Kitts and Nevis</option>
|
||||
<option value="Saint Lucia" {% if user.country == "Saint Lucia" %}selected{% endif %}>Saint Lucia</option>
|
||||
<option value="Saint Vincent and the Grenadines" {% if user.country == "Saint Vincent and the Grenadines" %}selected{% endif %}>Saint Vincent and the Grenadines</option>
|
||||
<option value="Samoa" {% if user.country == "Samoa" %}selected{% endif %}>Samoa</option>
|
||||
<option value="San Marino" {% if user.country == "San Marino" %}selected{% endif %}>San Marino</option>
|
||||
<option value="Sao Tome and Principe" {% if user.country == "Sao Tome and Principe" %}selected{% endif %}>Sao Tome and Principe</option>
|
||||
<option value="Saudi Arabia" {% if user.country == "Saudi Arabia" %}selected{% endif %}>Saudi Arabia</option>
|
||||
<option value="Senegal" {% if user.country == "Senegal" %}selected{% endif %}>Senegal</option>
|
||||
<option value="Serbia" {% if user.country == "Serbia" %}selected{% endif %}>Serbia</option>
|
||||
<option value="Seychelles" {% if user.country == "Seychelles" %}selected{% endif %}>Seychelles</option>
|
||||
<option value="Sierra Leone" {% if user.country == "Sierra Leone" %}selected{% endif %}>Sierra Leone</option>
|
||||
<option value="Singapore" {% if user.country == "Singapore" %}selected{% endif %}>Singapore</option>
|
||||
<option value="Slovakia" {% if user.country == "Slovakia" %}selected{% endif %}>Slovakia</option>
|
||||
<option value="Slovenia" {% if user.country == "Slovenia" %}selected{% endif %}>Slovenia</option>
|
||||
<option value="Solomon Islands" {% if user.country == "Solomon Islands" %}selected{% endif %}>Solomon Islands</option>
|
||||
<option value="Somalia" {% if user.country == "Somalia" %}selected{% endif %}>Somalia</option>
|
||||
<option value="South Africa" {% if user.country == "South Africa" %}selected{% endif %}>South Africa</option>
|
||||
<option value="South Korea" {% if user.country == "South Korea" %}selected{% endif %}>South Korea</option>
|
||||
<option value="South Sudan" {% if user.country == "South Sudan" %}selected{% endif %}>South Sudan</option>
|
||||
<option value="Spain" {% if user.country == "Spain" %}selected{% endif %}>Spain</option>
|
||||
<option value="Sri Lanka" {% if user.country == "Sri Lanka" %}selected{% endif %}>Sri Lanka</option>
|
||||
<option value="Sudan" {% if user.country == "Sudan" %}selected{% endif %}>Sudan</option>
|
||||
<option value="Suriname" {% if user.country == "Suriname" %}selected{% endif %}>Suriname</option>
|
||||
<option value="Sweden" {% if user.country == "Sweden" %}selected{% endif %}>Sweden</option>
|
||||
<option value="Switzerland" {% if user.country == "Switzerland" %}selected{% endif %}>Switzerland</option>
|
||||
<option value="Syria" {% if user.country == "Syria" %}selected{% endif %}>Syria</option>
|
||||
<option value="Taiwan" {% if user.country == "Taiwan" %}selected{% endif %}>Taiwan</option>
|
||||
<option value="Tajikistan" {% if user.country == "Tajikistan" %}selected{% endif %}>Tajikistan</option>
|
||||
<option value="Tanzania" {% if user.country == "Tanzania" %}selected{% endif %}>Tanzania</option>
|
||||
<option value="Thailand" {% if user.country == "Thailand" %}selected{% endif %}>Thailand</option>
|
||||
<option value="Timor-Leste" {% if user.country == "Timor-Leste" %}selected{% endif %}>Timor-Leste</option>
|
||||
<option value="Togo" {% if user.country == "Togo" %}selected{% endif %}>Togo</option>
|
||||
<option value="Tonga" {% if user.country == "Tonga" %}selected{% endif %}>Tonga</option>
|
||||
<option value="Trinidad and Tobago" {% if user.country == "Trinidad and Tobago" %}selected{% endif %}>Trinidad and Tobago</option>
|
||||
<option value="Tunisia" {% if user.country == "Tunisia" %}selected{% endif %}>Tunisia</option>
|
||||
<option value="Turkey" {% if user.country == "Turkey" %}selected{% endif %}>Turkey</option>
|
||||
<option value="Turkmenistan" {% if user.country == "Turkmenistan" %}selected{% endif %}>Turkmenistan</option>
|
||||
<option value="Tuvalu" {% if user.country == "Tuvalu" %}selected{% endif %}>Tuvalu</option>
|
||||
<option value="Uganda" {% if user.country == "Uganda" %}selected{% endif %}>Uganda</option>
|
||||
<option value="Ukraine" {% if user.country == "Ukraine" %}selected{% endif %}>Ukraine</option>
|
||||
<option value="United Arab Emirates" {% if user.country == "United Arab Emirates" %}selected{% endif %}>United Arab Emirates</option>
|
||||
<option value="United Kingdom" {% if user.country == "United Kingdom" %}selected{% endif %}>United Kingdom</option>
|
||||
<option value="United States" {% if user.country == "United States" %}selected{% endif %}>United States</option>
|
||||
<option value="Uruguay" {% if user.country == "Uruguay" %}selected{% endif %}>Uruguay</option>
|
||||
<option value="Uzbekistan" {% if user.country == "Uzbekistan" %}selected{% endif %}>Uzbekistan</option>
|
||||
<option value="Vanuatu" {% if user.country == "Vanuatu" %}selected{% endif %}>Vanuatu</option>
|
||||
<option value="Vatican City" {% if user.country == "Vatican City" %}selected{% endif %}>Vatican City</option>
|
||||
<option value="Venezuela" {% if user.country == "Venezuela" %}selected{% endif %}>Venezuela</option>
|
||||
<option value="Vietnam" {% if user.country == "Vietnam" %}selected{% endif %}>Vietnam</option>
|
||||
<option value="Yemen" {% if user.country == "Yemen" %}selected{% endif %}>Yemen</option>
|
||||
<option value="Zambia" {% if user.country == "Zambia" %}selected{% endif %}>Zambia</option>
|
||||
<option value="Zimbabwe" {% if user.country == "Zimbabwe" %}selected{% endif %}>Zimbabwe</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="timezone" class="col-sm-3 col-form-label">Time Zone</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-select" id="timezone" name="timezone">
|
||||
<option value="">Choose timezone...</option>
|
||||
<option value="UTC-12:00" {% if user.timezone == "UTC-12:00" %}selected{% endif %}>UTC-12:00 (Baker Island)</option>
|
||||
<option value="UTC-11:00" {% if user.timezone == "UTC-11:00" %}selected{% endif %}>UTC-11:00 (American Samoa, Niue)</option>
|
||||
<option value="UTC-10:00" {% if user.timezone == "UTC-10:00" %}selected{% endif %}>UTC-10:00 (Hawaii-Aleutian Standard Time)</option>
|
||||
<option value="UTC-09:30" {% if user.timezone == "UTC-09:30" %}selected{% endif %}>UTC-09:30 (Marquesas Islands)</option>
|
||||
<option value="UTC-09:00" {% if user.timezone == "UTC-09:00" %}selected{% endif %}>UTC-09:00 (Alaska Standard Time)</option>
|
||||
<option value="UTC-08:00" {% if user.timezone == "UTC-08:00" %}selected{% endif %}>UTC-08:00 (Pacific Standard Time - Los Angeles, Vancouver)</option>
|
||||
<option value="UTC-07:00" {% if user.timezone == "UTC-07:00" %}selected{% endif %}>UTC-07:00 (Mountain Standard Time - Denver, Calgary)</option>
|
||||
<option value="UTC-06:00" {% if user.timezone == "UTC-06:00" %}selected{% endif %}>UTC-06:00 (Central Standard Time - Chicago, Mexico City)</option>
|
||||
<option value="UTC-05:00" {% if user.timezone == "UTC-05:00" %}selected{% endif %}>UTC-05:00 (Eastern Standard Time - New York, Toronto)</option>
|
||||
<option value="UTC-04:00" {% if user.timezone == "UTC-04:00" %}selected{% endif %}>UTC-04:00 (Atlantic Standard Time - Halifax, Caracas)</option>
|
||||
<option value="UTC-03:30" {% if user.timezone == "UTC-03:30" %}selected{% endif %}>UTC-03:30 (Newfoundland Standard Time)</option>
|
||||
<option value="UTC-03:00" {% if user.timezone == "UTC-03:00" %}selected{% endif %}>UTC-03:00 (Argentina, Brazil, Uruguay)</option>
|
||||
<option value="UTC-02:00" {% if user.timezone == "UTC-02:00" %}selected{% endif %}>UTC-02:00 (South Georgia and the South Sandwich Islands)</option>
|
||||
<option value="UTC-01:00" {% if user.timezone == "UTC-01:00" %}selected{% endif %}>UTC-01:00 (Azores, Cape Verde)</option>
|
||||
<option value="UTC+00:00" {% if user.timezone == "UTC+00:00" %}selected{% endif %}>UTC+00:00 (Greenwich Mean Time - London, Dublin, Lisbon)</option>
|
||||
<option value="UTC+01:00" {% if user.timezone == "UTC+01:00" %}selected{% endif %}>UTC+01:00 (Central European Time - Berlin, Paris, Rome)</option>
|
||||
<option value="UTC+02:00" {% if user.timezone == "UTC+02:00" %}selected{% endif %}>UTC+02:00 (Eastern European Time - Athens, Cairo, Helsinki)</option>
|
||||
<option value="UTC+03:00" {% if user.timezone == "UTC+03:00" %}selected{% endif %}>UTC+03:00 (Moscow Standard Time - Moscow, Istanbul, Nairobi)</option>
|
||||
<option value="UTC+03:30" {% if user.timezone == "UTC+03:30" %}selected{% endif %}>UTC+03:30 (Iran Standard Time - Tehran)</option>
|
||||
<option value="UTC+04:00" {% if user.timezone == "UTC+04:00" %}selected{% endif %}>UTC+04:00 (Gulf Standard Time - Dubai, Baku)</option>
|
||||
<option value="UTC+04:30" {% if user.timezone == "UTC+04:30" %}selected{% endif %}>UTC+04:30 (Afghanistan Time - Kabul)</option>
|
||||
<option value="UTC+05:00" {% if user.timezone == "UTC+05:00" %}selected{% endif %}>UTC+05:00 (Pakistan Standard Time - Karachi, Tashkent)</option>
|
||||
<option value="UTC+05:30" {% if user.timezone == "UTC+05:30" %}selected{% endif %}>UTC+05:30 (India Standard Time - Mumbai, Delhi, Colombo)</option>
|
||||
<option value="UTC+05:45" {% if user.timezone == "UTC+05:45" %}selected{% endif %}>UTC+05:45 (Nepal Time - Kathmandu)</option>
|
||||
<option value="UTC+06:00" {% if user.timezone == "UTC+06:00" %}selected{% endif %}>UTC+06:00 (Bangladesh Standard Time - Dhaka, Almaty)</option>
|
||||
<option value="UTC+06:30" {% if user.timezone == "UTC+06:30" %}selected{% endif %}>UTC+06:30 (Myanmar Time - Yangon, Cocos Islands)</option>
|
||||
<option value="UTC+07:00" {% if user.timezone == "UTC+07:00" %}selected{% endif %}>UTC+07:00 (Indochina Time - Bangkok, Jakarta, Ho Chi Minh City)</option>
|
||||
<option value="UTC+08:00" {% if user.timezone == "UTC+08:00" %}selected{% endif %}>UTC+08:00 (China Standard Time - Beijing, Singapore, Manila)</option>
|
||||
<option value="UTC+08:45" {% if user.timezone == "UTC+08:45" %}selected{% endif %}>UTC+08:45 (Australian Central Western Standard Time)</option>
|
||||
<option value="UTC+09:00" {% if user.timezone == "UTC+09:00" %}selected{% endif %}>UTC+09:00 (Japan Standard Time - Tokyo, Seoul, Pyongyang)</option>
|
||||
<option value="UTC+09:30" {% if user.timezone == "UTC+09:30" %}selected{% endif %}>UTC+09:30 (Australian Central Standard Time - Adelaide, Darwin)</option>
|
||||
<option value="UTC+10:00" {% if user.timezone == "UTC+10:00" %}selected{% endif %}>UTC+10:00 (Australian Eastern Standard Time - Sydney, Melbourne)</option>
|
||||
<option value="UTC+10:30" {% if user.timezone == "UTC+10:30" %}selected{% endif %}>UTC+10:30 (Lord Howe Standard Time)</option>
|
||||
<option value="UTC+11:00" {% if user.timezone == "UTC+11:00" %}selected{% endif %}>UTC+11:00 (Solomon Islands, New Caledonia)</option>
|
||||
<option value="UTC+12:00" {% if user.timezone == "UTC+12:00" %}selected{% endif %}>UTC+12:00 (New Zealand Standard Time - Auckland, Fiji)</option>
|
||||
<option value="UTC+12:45" {% if user.timezone == "UTC+12:45" %}selected{% endif %}>UTC+12:45 (Chatham Standard Time)</option>
|
||||
<option value="UTC+13:00" {% if user.timezone == "UTC+13:00" %}selected{% endif %}>UTC+13:00 (Tonga, Samoa)</option>
|
||||
<option value="UTC+14:00" {% if user.timezone == "UTC+14:00" %}selected{% endif %}>UTC+14:00 (Line Islands, Kiribati)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="tab-pane fade" id="v-pills-password" role="tabpanel" aria-labelledby="v-pills-password-tab">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Change Password</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="passwordForm">
|
||||
<div class="row mb-3">
|
||||
<label for="current-password" class="col-sm-3 col-form-label">Current Password</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" id="current-password" name="current_password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="new-password" class="col-sm-3 col-form-label">New Password</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" id="new-password" name="new_password" minlength="12" required>
|
||||
<small class="text-muted">Password must be at least 12 characters long with a mix of letters, numbers, and special characters</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label for="confirm-password" class="col-sm-3 col-form-label">Confirm Password</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" id="confirm-password" name="confirm_password" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">Update Password</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Keys -->
|
||||
<div class="tab-pane fade" id="v-pills-ssh-keys" role="tabpanel" aria-labelledby="v-pills-ssh-keys-tab">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5>SSH Keys</h5>
|
||||
<button type="button" class="btn btn-primary btn-sm" id="addSSHKeyBtn">
|
||||
<i class="bi bi-plus-circle me-1"></i>Add SSH Key
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>SSH Keys for Self-Managed Resources:</strong> Upload your SSH public keys to access self-managed VMs and Kubernetes clusters. Your keys are stored securely and can be used across multiple deployments.
|
||||
</div>
|
||||
|
||||
<!-- SSH Keys List -->
|
||||
<div id="sshKeysList">
|
||||
<div class="text-center p-4" id="noSSHKeysMessage">
|
||||
<i class="bi bi-key display-4 text-muted"></i>
|
||||
<p class="mt-2 text-muted">No SSH keys found. Add your first SSH key to get started.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Key Template (hidden, used for JS cloning) -->
|
||||
<div class="d-none" id="sshKeyTemplate">
|
||||
<div class="card mb-3 ssh-key-item" data-key-id="">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-key me-2 text-primary"></i>
|
||||
<div>
|
||||
<h6 class="mb-1 ssh-key-name">Key Name</h6>
|
||||
<small class="text-muted ssh-key-type">Key Type</small>
|
||||
<span class="badge bg-success ms-2 ssh-key-default d-none">Default</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<small class="text-muted">
|
||||
<strong>Fingerprint:</strong> <code class="ssh-key-fingerprint">SHA256:...</code>
|
||||
</small>
|
||||
</div>
|
||||
<div class="mt-1">
|
||||
<small class="text-muted ssh-key-created">Added: Never</small>
|
||||
<small class="text-muted ssh-key-last-used ms-3">Last used: Never</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm set-default-btn">
|
||||
Set Default
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm edit-ssh-key-btn">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-danger btn-sm delete-ssh-key-btn">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Currency Preferences -->
|
||||
<div class="tab-pane fade" id="v-pills-currency" role="tabpanel" aria-labelledby="v-pills-currency-tab">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5>Currency Preferences</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="currencyForm">
|
||||
<div class="row mb-4">
|
||||
<label for="displayCurrency" class="col-sm-3 col-form-label">Display Currency</label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-select" id="displayCurrency" name="display_currency">
|
||||
<option value="USD" {% if user_display_currency == "USD" %}selected{% endif %}>USD - US Dollar</option>
|
||||
<option value="TFC" {% if user_display_currency == "TFC" %}selected{% endif %}>TFC - ThreeFold Credits</option>
|
||||
<option value="EUR" {% if user_display_currency == "EUR" %}selected{% endif %}>EUR - Euro</option>
|
||||
<option value="CAD" {% if user_display_currency == "CAD" %}selected{% endif %}>CAD - Canadian Dollar</option>
|
||||
</select>
|
||||
<small class="text-muted">Choose your preferred currency for displaying prices in the marketplace</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>Note:</strong> All transactions are processed in USD Credits. Display currency is used for convenience only and prices are converted in real-time.
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary">Save Currency Preferences</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Account -->
|
||||
<div class="tab-pane fade" id="v-pills-delete" role="tabpanel" aria-labelledby="v-pills-delete-tab">
|
||||
<div class="card border-danger">
|
||||
<div class="card-header bg-danger text-white">
|
||||
<h5>Delete Account</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-warning">
|
||||
<h5><i class="bi bi-exclamation-triangle me-2"></i>Warning: This action is irreversible</h5>
|
||||
<p>Deleting your account will permanently remove all your data, including:</p>
|
||||
<ul>
|
||||
<li>Your profile information</li>
|
||||
<li>Your deployment configurations</li>
|
||||
<li>Your billing history</li>
|
||||
</ul>
|
||||
<p class="mb-0"><strong>Note:</strong> Any active deployments must be manually terminated before account deletion.</p>
|
||||
</div>
|
||||
<form id="deleteAccountForm" class="mt-4">
|
||||
<div class="mb-3">
|
||||
<label for="deleteConfirmation" class="form-label">Type "DELETE" to confirm</label>
|
||||
<input type="text" class="form-control" id="deleteConfirmation" name="confirmation" placeholder="Type DELETE in all caps" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="deletePassword" class="form-label">Your current password</label>
|
||||
<input type="password" class="form-control" id="deletePassword" name="password" required>
|
||||
<div id="deletePasswordFeedback" class="invalid-feedback">Incorrect password.</div>
|
||||
</div>
|
||||
<div class="mb-3 form-check">
|
||||
<input type="checkbox" class="form-check-input" id="deleteCheck" required>
|
||||
<label class="form-check-label" for="deleteCheck">I understand this action cannot be undone</label>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-danger">Delete My Account</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom Delete Confirmation Modal -->
|
||||
<div class="modal fade" id="deleteConfirmationModal" tabindex="-1" aria-labelledby="deleteConfirmationModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content border-danger">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title" id="deleteConfirmationModalLabel">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>Final Confirmation Required
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-warning">
|
||||
<h6><strong>This is your final warning!</strong></h6>
|
||||
<p class="mb-0">You are about to permanently delete your account. This action will:</p>
|
||||
</div>
|
||||
<ul class="mb-3">
|
||||
<li>Mark your account as deleted (data preserved for recovery)</li>
|
||||
<li>Prevent you from logging in</li>
|
||||
<li>Hide your services and apps from the marketplace</li>
|
||||
<li>Require administrator assistance to recover</li>
|
||||
</ul>
|
||||
<div class="mb-3">
|
||||
<label class="form-label"><strong>Type "I UNDERSTAND" to proceed:</strong></label>
|
||||
<input type="text" class="form-control" id="finalConfirmationInput" placeholder="Type I UNDERSTAND">
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<p class="text-muted mb-0">Deletion will proceed in <span id="countdownTimer" class="fw-bold text-danger">10</span> seconds after confirmation</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="finalDeleteButton" disabled>
|
||||
<span id="deleteButtonText">Confirm Deletion</span>
|
||||
<span id="deleteButtonSpinner" class="spinner-border spinner-border-sm ms-2 d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Key Management Modals -->
|
||||
|
||||
<!-- Add SSH Key Modal -->
|
||||
<div class="modal fade" id="addSSHKeyModal" tabindex="-1" aria-labelledby="addSSHKeyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="addSSHKeyModalLabel">
|
||||
<i class="bi bi-key me-2"></i>Add SSH Key
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="addSSHKeyForm">
|
||||
<div class="mb-3">
|
||||
<label for="sshKeyName" class="form-label">Key Name</label>
|
||||
<input type="text" class="form-control" id="sshKeyName" name="name" placeholder="e.g., MacBook Pro, Work Laptop" required>
|
||||
<div class="form-text">Choose a descriptive name to identify this key</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="sshPublicKey" class="form-label">SSH Public Key</label>
|
||||
<textarea class="form-control" id="sshPublicKey" name="public_key" rows="4" placeholder="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... user@example.com" required></textarea>
|
||||
<div class="form-text">
|
||||
Paste your SSH public key here. Supported formats: Ed25519, ECDSA, RSA (2048+ bits)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="setAsDefault" name="is_default">
|
||||
<label class="form-check-label" for="setAsDefault">
|
||||
Set as default key for new deployments
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>How to find your SSH public key:</strong>
|
||||
<ul class="mb-0 mt-2">
|
||||
<li><strong>Linux/macOS:</strong> <code>cat ~/.ssh/id_ed25519.pub</code> or <code>cat ~/.ssh/id_rsa.pub</code></li>
|
||||
<li><strong>Windows:</strong> <code>type %USERPROFILE%\.ssh\id_ed25519.pub</code></li>
|
||||
<li><strong>Generate new key:</strong> <code>ssh-keygen -t ed25519 -C "your_email@example.com"</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Key validation feedback -->
|
||||
<div id="keyValidationFeedback" class="d-none">
|
||||
<div class="alert alert-success" id="keyValidationSuccess">
|
||||
<i class="bi bi-check-circle me-2"></i>
|
||||
<span id="keyValidationSuccessText">Valid SSH key detected!</span>
|
||||
</div>
|
||||
<div class="alert alert-danger" id="keyValidationError">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<span id="keyValidationErrorText">Invalid SSH key format</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="addSSHKeyForm" class="btn btn-primary" id="addSSHKeySubmit">
|
||||
<span id="addSSHKeyText">Add SSH Key</span>
|
||||
<span id="addSSHKeySpinner" class="spinner-border spinner-border-sm ms-2 d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit SSH Key Modal -->
|
||||
<div class="modal fade" id="editSSHKeyModal" tabindex="-1" aria-labelledby="editSSHKeyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editSSHKeyModalLabel">
|
||||
<i class="bi bi-pencil me-2"></i>Edit SSH Key
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editSSHKeyForm">
|
||||
<input type="hidden" id="editSSHKeyId" name="keyId">
|
||||
<div class="mb-3">
|
||||
<label for="editSSHKeyName" class="form-label">Key Name</label>
|
||||
<input type="text" class="form-control" id="editSSHKeyName" name="name" required>
|
||||
<div class="form-text">Choose a descriptive name to identify this key</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="editSetAsDefault" name="is_default">
|
||||
<label class="form-check-label" for="editSetAsDefault">
|
||||
Set as default key for new deployments
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="editSSHKeyForm" class="btn btn-primary" id="editSSHKeySubmit">
|
||||
<span id="editSSHKeyText">Update SSH Key</span>
|
||||
<span id="editSSHKeySpinner" class="spinner-border spinner-border-sm ms-2 d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete SSH Key Modal -->
|
||||
<div class="modal fade" id="deleteSSHKeyModal" tabindex="-1" aria-labelledby="deleteSSHKeyModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deleteSSHKeyModalLabel">
|
||||
<i class="bi bi-trash me-2"></i>Delete SSH Key
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="deleteSSHKeyForm">
|
||||
<input type="hidden" id="deleteSSHKeyId" name="keyId">
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<strong>Are you sure?</strong>
|
||||
</div>
|
||||
<p>You are about to delete the SSH key:</p>
|
||||
<p><strong id="deleteSSHKeyName">Key Name</strong></p>
|
||||
<p class="text-muted">This action cannot be undone. If this key is currently used for deployments, you may lose access to those resources.</p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" form="deleteSSHKeyForm" class="btn btn-danger" id="deleteSSHKeySubmit">
|
||||
<span id="deleteSSHKeyText">Delete SSH Key</span>
|
||||
<span id="deleteSSHKeySpinner" class="spinner-border spinner-border-sm ms-2 d-none" role="status"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SSH Keys Data Hydration -->
|
||||
<script type="application/json" id="ssh-keys-data">{{ ssh_keys_json | default(value="[]") | safe }}</script>
|
||||
|
||||
<script src="/static/js/dashboard-settings.js"></script>
|
||||
|
||||
<!-- SSH Key Management Script -->
|
||||
<script src="/static/js/dashboard-ssh-keys.js"></script>
|
||||
{% endblock %}
|
||||
492
src/views/dashboard/user.html
Normal file
492
src/views/dashboard/user.html
Normal file
@@ -0,0 +1,492 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - User{% endblock %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="my-4">
|
||||
<h1>User Dashboard</h1>
|
||||
<p class="lead">Manage your applications, resources, and monitor usage</p>
|
||||
|
||||
<!-- Status Summary -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h5 class="card-title">Active Apps</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ active_applications_count | default(value=0) }}</h2>
|
||||
<small class="text-muted">Deployments</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h5 class="card-title">Slices</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ active_compute_resources_count | default(value=0) }}</h2>
|
||||
<small class="text-muted">Active Resources</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h5 class="card-title">Uptime</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ average_sla_percentage | default(value=99.0) | round(precision=1) }}%</h2>
|
||||
<small class="text-muted">Average</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h5 class="card-title">Cost Rate</h5>
|
||||
<div class="d-flex justify-content-between align-items-end">
|
||||
<h2 class="mb-0">{{ total_monthly_cost | default(value=0) | format_decimal(precision=2) }}</h2>
|
||||
<small class="text-muted">{{ currency_symbol | default(value="$") }}/month</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Quick Actions</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<a href="/marketplace/applications" class="btn btn-primary w-100 mb-2">
|
||||
<i class="bi bi-box-seam me-2"></i> Deploy Applications
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<a href="/marketplace/compute" class="btn btn-success w-100 mb-2">
|
||||
<i class="bi bi-cpu me-2"></i> Deploy Slices
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Applications Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>My Applications</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th>Uptime</th>
|
||||
<th>Resources</th>
|
||||
<th>Cost</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="applications-table">
|
||||
<tr>
|
||||
<td colspan="7" class="text-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
Loading applications...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Compute Resources (Slices) Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h3>My Compute Resources</h3>
|
||||
<a href="/marketplace/compute" class="btn btn-outline-primary">
|
||||
<i class="bi bi-plus-circle me-2"></i> Reserve More Resources
|
||||
</a>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Resource ID</th>
|
||||
<th>Type</th>
|
||||
<th>Specs</th>
|
||||
<th>Location</th>
|
||||
<th>Status</th>
|
||||
<th>SLA</th>
|
||||
<th>Cost</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="compute-resources-table">
|
||||
<tr>
|
||||
<td colspan="8" class="text-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
Loading compute resources...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Slice Rentals Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h3>My Slice Rentals</h3>
|
||||
<div>
|
||||
<button type="button" class="btn btn-outline-secondary me-2" id="refresh-slice-rentals">
|
||||
<i class="fas fa-sync-alt me-1"></i> Refresh
|
||||
</button>
|
||||
<a href="/marketplace/compute" class="btn btn-outline-primary">
|
||||
<i class="fas fa-plus me-1"></i> Rent More Slices
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Slice Rentals Stats -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h6 class="card-title">Active Rentals</h6>
|
||||
<h4 class="mb-0" id="active-rentals-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h6 class="card-title">VM Deployments</h6>
|
||||
<h4 class="mb-0" id="vm-deployments-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h6 class="card-title">Kubernetes Clusters</h6>
|
||||
<h4 class="mb-0" id="k8s-deployments-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h6 class="card-title">Monthly Cost</h6>
|
||||
<h4 class="mb-0" id="slice-monthly-cost">$0</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Slice Rentals Cards Container -->
|
||||
<div class="row" id="slice-rentals-container">
|
||||
<div class="col-12 text-center py-5">
|
||||
<div class="spinner-border text-primary me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<span class="text-muted">Loading slice rentals...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Deployment Management Modal -->
|
||||
<div class="modal fade" id="deploymentModal" tabindex="-1" aria-labelledby="deploymentModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="deploymentModalLabel">Manage Deployment</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Content will be populated by JavaScript -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cancel Rental Modal -->
|
||||
<div class="modal fade" id="cancelModal" tabindex="-1" aria-labelledby="cancelModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="cancelModalLabel">Cancel Slice Rental</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Content will be populated by JavaScript -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmCancelBtn">Confirm Cancellation</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Bookings Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h3>My Service Bookings</h3>
|
||||
<a href="/marketplace/services" class="btn btn-outline-primary">
|
||||
<i class="bi bi-plus-circle me-2"></i> Book More Services
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Service Bookings Stats (populated by JS) -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card primary">
|
||||
<h6 class="card-title">Active Bookings</h6>
|
||||
<h4 class="mb-0" id="active-bookings-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card success">
|
||||
<h6 class="card-title">Completed</h6>
|
||||
<h4 class="mb-0" id="completed-bookings-count">0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card info">
|
||||
<h6 class="card-title">Total Spent</h6>
|
||||
<h4 class="mb-0" id="total-spent">$0</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="stats-card warning">
|
||||
<h6 class="card-title">Monthly Spending</h6>
|
||||
<h4 class="mb-0" id="monthly-spending">$0</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Bookings Table (populated by JS) -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Service</th>
|
||||
<th>Provider</th>
|
||||
<th>Status</th>
|
||||
<th>Progress</th>
|
||||
<th>Budget</th>
|
||||
<th>Requested Date</th>
|
||||
<th>Priority</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="service-bookings-tbody">
|
||||
<tr>
|
||||
<td colspan="8" class="text-center text-muted">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
Loading service bookings...
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Favorite Providers (optional, populated by JS if available) -->
|
||||
<div class="mt-4" id="favorite-providers-section" style="display: none;">
|
||||
<h5>Favorite Providers</h5>
|
||||
<div class="d-flex flex-wrap gap-2" id="favorite-providers"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Usage Monitoring Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Usage Monitoring</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Credits Usage Trend</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="creditsUsageChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Resource Utilization</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="resourceUtilizationChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Charts Row -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>User Activity Trends</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="userActivityChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5>Deployment Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="deploymentDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activities Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Recent Activities</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Action</th>
|
||||
<th>Status</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="recent-activities-tbody">
|
||||
<!-- Activities will be populated by JavaScript -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Resource Utilization Progress Bars -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Current Resource Utilization</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span class="text-muted">CPU Usage</span>
|
||||
<span id="cpu-percentage" class="fw-bold">0%</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="cpu-progress" class="progress-bar bg-primary" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span class="text-muted">Memory Usage</span>
|
||||
<span id="memory-percentage" class="fw-bold">0%</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="memory-progress" class="progress-bar bg-success" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span class="text-muted">Storage Usage</span>
|
||||
<span id="storage-percentage" class="fw-bold">0%</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="storage-progress" class="progress-bar bg-warning" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span class="text-muted">Network Usage</span>
|
||||
<span id="network-percentage" class="fw-bold">0%</span>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div id="network-progress" class="progress-bar bg-danger" role="progressbar" style="width: 0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Service Booking Details Modal -->
|
||||
<div class="modal fade" id="bookingDetailsModal" tabindex="-1" aria-labelledby="bookingDetailsModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="bookingDetailsModalLabel">Service Booking Details</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="bookingDetailsContent">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
<p class="mt-2">Loading booking details...</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" id="contactProviderBtn" style="display: none;">
|
||||
<i class="bi bi-chat-dots me-1"></i> Contact Provider
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
|
||||
<!-- Load dashboard JavaScript -->
|
||||
<script src="/static/js/dashboard-user.js"></script>
|
||||
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card-body {
|
||||
min-height: 340px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
442
src/views/dashboard/wallet.html
Normal file
442
src/views/dashboard/wallet.html
Normal file
@@ -0,0 +1,442 @@
|
||||
{% extends "dashboard/layout.html" %}
|
||||
|
||||
{% block dashboard_content %}
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">Credits Wallet</h1>
|
||||
</div>
|
||||
|
||||
<!-- Wallet Balance Card -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card bg-primary text-white">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<i class="bi bi-coin"></i> Current Balance
|
||||
</h5>
|
||||
<h2 class="card-text" id="wallet-balance">
|
||||
{% if wallet_balance %}
|
||||
{{ currency_symbol | default(value="$") }}{{ wallet_balance | format_decimal(precision=2) }}
|
||||
{% else %}
|
||||
{{ currency_symbol | default(value="$") }}0.00
|
||||
{% endif %}
|
||||
</h2>
|
||||
<small class="text-light">Credits ({{ display_currency | default(value="USD") }})</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card bg-success text-white">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<i class="bi bi-graph-up"></i> Available Balance
|
||||
</h5>
|
||||
<h2 class="card-text" id="usd-equivalent">
|
||||
{% if wallet_balance %}
|
||||
{{ currency_symbol | default(value="$") }}{{ wallet_balance | format_decimal(precision=2) }}
|
||||
{% else %}
|
||||
{{ currency_symbol | default(value="$") }}0.00
|
||||
{% endif %}
|
||||
</h2>
|
||||
<small class="text-light">Ready to spend</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Wallet Actions</h5>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#buyCreditsModal">
|
||||
<i class="bi bi-plus-circle"></i> Buy Credits
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#transferCreditsModal">
|
||||
<i class="bi bi-send"></i> Transfer Credits
|
||||
</button>
|
||||
<button type="button" class="btn btn-info" data-action="refresh-wallet">
|
||||
<i class="bi bi-arrow-clockwise"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Auto Top-Up Settings -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-lightning-charge"></i> Auto Top-Up Settings
|
||||
</h5>
|
||||
<span class="badge bg-secondary" id="autoTopUpStatus">Loading...</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="autoTopUpContent">
|
||||
<div class="d-flex justify-content-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<button type="button" class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#configureAutoTopUpModal">
|
||||
<i class="bi bi-gear"></i> Configure Auto Top-Up
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Owned Products and Active Rentals -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-box"></i> Owned Products
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if owned_products and owned_products|length > 0 %}
|
||||
<div class="list-group list-group-flush">
|
||||
{% for product_id in owned_products %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<strong>Product {{ product_id }}</strong><br>
|
||||
<small class="text-muted">Owned Product</small>
|
||||
</div>
|
||||
<span class="badge bg-success rounded-pill">Owned</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted">No owned products yet.</p>
|
||||
<a href="/marketplace" class="btn btn-outline-primary btn-sm">Browse Marketplace</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-clock"></i> Active Rentals
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if active_rentals and active_rentals|length > 0 %}
|
||||
<div class="list-group list-group-flush">
|
||||
{% for rental_id in active_rentals %}
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<strong>Rental {{ rental_id }}</strong><br>
|
||||
<small class="text-muted">Active Rental</small>
|
||||
</div>
|
||||
<span class="badge bg-primary rounded-pill">Active</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<p class="text-muted">No active rentals.</p>
|
||||
<a href="/marketplace" class="btn btn-outline-primary btn-sm">Browse Marketplace</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Transactions -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="bi bi-clock-history"></i> Recent Transactions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="transactions-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Type</th>
|
||||
<th>Amount ({{ currency_symbol | default(value="$") }})</th>
|
||||
<th>Status</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="transactions-tbody">
|
||||
{% if transaction_history %}
|
||||
{% for transaction in transaction_history %}
|
||||
<tr>
|
||||
<td>{{ transaction.formatted_timestamp }}</td>
|
||||
<td>
|
||||
{% if transaction.transaction_type.CreditsPurchase %}
|
||||
<span class="badge bg-success">Credits Purchase</span>
|
||||
{% elif transaction.transaction_type.CreditsSale %}
|
||||
<span class="badge bg-danger">Credits Sale</span>
|
||||
{% elif transaction.transaction_type.Rental %}
|
||||
<span class="badge bg-primary">Rental</span>
|
||||
{% elif transaction.transaction_type.Purchase %}
|
||||
<span class="badge bg-danger">Purchase</span>
|
||||
{% elif transaction.transaction_type.InstantPurchase %}
|
||||
<span class="badge bg-danger">Purchase</span>
|
||||
{% elif transaction.transaction_type.CreditsTransfer or transaction.transaction_type.Transfer %}
|
||||
<span class="badge bg-info">Credits Transfer</span>
|
||||
{% elif transaction.transaction_type.Earning %}
|
||||
<span class="badge bg-success">Earning</span>
|
||||
{% elif transaction.transaction_type.Exchange %}
|
||||
<span class="badge bg-secondary">Exchange</span>
|
||||
{% elif transaction.transaction_type.Stake %}
|
||||
<span class="badge bg-primary">Stake</span>
|
||||
{% elif transaction.transaction_type.Unstake %}
|
||||
<span class="badge bg-warning">Unstake</span>
|
||||
{% else %}
|
||||
<span class="badge bg-light text-dark">Unknown</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if transaction.transaction_type.CreditsPurchase or transaction.transaction_type.Earning or transaction.transaction_type.Unstake %}
|
||||
<span class="text-success">+{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% elif transaction.transaction_type.CreditsSale %}
|
||||
<span class="text-danger">-{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% elif transaction.transaction_type.Exchange %}
|
||||
{% if transaction.amount > 0 %}
|
||||
<span class="text-success">+{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% else %}
|
||||
<span class="text-danger">-{{ transaction.amount | abs | format_decimal(precision=2) }}</span>
|
||||
{% endif %}
|
||||
{% elif transaction.transaction_type.Purchase or transaction.transaction_type.InstantPurchase or transaction.transaction_type.Rental or transaction.transaction_type.Transfer or transaction.transaction_type.CreditsTransfer or transaction.transaction_type.Stake %}
|
||||
<span class="text-danger">-{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% else %}
|
||||
<span class="text-muted">{{ transaction.amount | format_decimal(precision=2) }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if transaction.status == "Completed" %}
|
||||
<span class="badge bg-success">{{ transaction.status }}</span>
|
||||
{% elif transaction.status == "Pending" %}
|
||||
<span class="badge bg-warning">{{ transaction.status }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger">{{ transaction.status }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ transaction.id }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="5" class="text-center text-muted">No transactions yet</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy Credits Modal -->
|
||||
<div class="modal fade" id="buyCreditsModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Buy Credits</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="buyCreditsForm">
|
||||
<div class="mb-3">
|
||||
<label for="creditsAmount" class="form-label">Amount ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="creditsAmount" min="1" max="10000" step="1" required>
|
||||
<div class="form-text">Minimum: {{ currency_symbol | default(value="$") }}1, Maximum: {{ currency_symbol | default(value="$") }}10,000</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="paymentMethod" class="form-label">Payment Method</label>
|
||||
<select class="form-select" id="paymentMethod" required>
|
||||
<option value="">Select payment method</option>
|
||||
<option value="credit_card">Credit Card</option>
|
||||
<option value="paypal">PayPal</option>
|
||||
<option value="bank_transfer">Bank Transfer</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="alert alert-info">
|
||||
<strong>Rate:</strong> 1 Credit = {{ currency_symbol | default(value="$") }}1 {{ display_currency | default(value="USD") }}<br>
|
||||
<strong>Total Cost:</strong> {{ currency_symbol | default(value="$") }}<span id="totalCost">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="buy-credits">Purchase Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transfer Credits Modal -->
|
||||
<div class="modal fade" id="transferCreditsModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Transfer Credits</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="transferCreditsForm">
|
||||
<div class="mb-3">
|
||||
<label for="recipientEmail" class="form-label">Recipient Email</label>
|
||||
<input type="email" class="form-control" id="recipientEmail" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="transferAmount" class="form-label">Amount ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="transferAmount" min="1" step="1" required>
|
||||
<div class="form-text">Available balance: {{ currency_symbol | default(value="$") }}<span id="availableBalance">{% if wallet_balance %}{{ wallet_balance | format_decimal(precision=2) }}{% else %}0.00{% endif %}</span></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="transferNote" class="form-label">Note (Optional)</label>
|
||||
<textarea class="form-control" id="transferNote" rows="2" placeholder="Add a note for this transfer"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="transfer-credits">Send Transfer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Configure Auto Top-Up Modal -->
|
||||
<div class="modal fade" id="configureAutoTopUpModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">
|
||||
<i class="bi bi-lightning-charge"></i> Configure Auto Top-Up
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="autoTopUpForm">
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" id="autoTopUpEnabled">
|
||||
<label class="form-check-label" for="autoTopUpEnabled">
|
||||
<strong>Enable Auto Top-Up</strong>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-text">Automatically add credits when your balance falls below the threshold</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="autoTopUpSettings" style="display: none;">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="thresholdAmount" class="form-label">Threshold Amount ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="thresholdAmount" min="1" max="1000" step="1" value="10">
|
||||
<div class="form-text">Trigger auto top-up when balance falls below this amount</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="topUpAmount" class="form-label">Top-Up Amount ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="topUpAmount" min="5" max="1000" step="5" value="50">
|
||||
<div class="form-text">Amount to add when auto top-up is triggered</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-3">
|
||||
<label for="autoTopUpPaymentMethod" class="form-label">Payment Method</label>
|
||||
<select class="form-select" id="autoTopUpPaymentMethod" required>
|
||||
<option value="">Select payment method</option>
|
||||
<option value="credit_card">Credit Card</option>
|
||||
<option value="paypal">PayPal</option>
|
||||
<option value="bank_transfer">Bank Transfer</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="dailyLimit" class="form-label">Daily Limit ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="dailyLimit" min="0" max="5000" step="10" value="200">
|
||||
<div class="form-text">Maximum auto top-up per day (0 = no limit)</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="monthlyLimit" class="form-label">Monthly Limit ({{ currency_symbol | default(value="$") }})</label>
|
||||
<input type="number" class="form-control" id="monthlyLimit" min="0" max="50000" step="50" value="2000">
|
||||
<div class="form-text">Maximum auto top-up per month (0 = no limit)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<h6 class="alert-heading">
|
||||
<i class="bi bi-info-circle"></i> How Auto Top-Up Works
|
||||
</h6>
|
||||
<ul class="mb-0">
|
||||
<li>When your balance falls below the threshold, we'll automatically add the specified top-up amount</li>
|
||||
<li>Auto top-up only triggers during purchase attempts, not continuously</li>
|
||||
<li>Daily and monthly limits help control spending</li>
|
||||
<li>You can disable auto top-up at any time</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" data-action="save-auto-topup-settings">
|
||||
<i class="bi bi-check-lg"></i> Save Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Toast Container for Success Messages -->
|
||||
<div class="toast-container position-fixed bottom-0 end-0 p-3">
|
||||
<div id="successToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-success text-white">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
<strong class="me-auto">Success</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="successToastBody">
|
||||
Operation completed successfully!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="errorToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header bg-danger text-white">
|
||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
||||
<strong class="me-auto">Error</strong>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body" id="errorToastBody">
|
||||
An error occurred!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="application/json" id="wallet-hydration">
|
||||
{
|
||||
"currency_symbol": {{ currency_symbol | default(value='$') | json_encode() }},
|
||||
"display_currency": {{ display_currency | default(value='USD') | json_encode() }}
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/dashboard_wallet.js"></script>
|
||||
{% endblock %}
|
||||
91
src/views/dashboard/welcome.html
Normal file
91
src/views/dashboard/welcome.html
Normal file
@@ -0,0 +1,91 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}ThreeFold Dashboard - Welcome{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container py-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-10">
|
||||
<div class="card shadow-lg border-0">
|
||||
<div class="card-body p-5">
|
||||
<div class="text-center mb-5">
|
||||
<h1 class="display-4 fw-bold text-primary">Welcome to ThreeFold Dashboard</h1>
|
||||
<p class="lead text-muted">Your central hub for managing your ThreeFold experience</p>
|
||||
</div>
|
||||
|
||||
<div class="row mb-5 align-items-center">
|
||||
<div class="col-md-6 text-center">
|
||||
<img src="/static/images/dashboard-illustration.svg" alt="Dashboard Illustration" class="img-fluid" onerror="this.src='/static/images/logo_light.png'; this.onerror=null;">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h2>Access Your Dashboard</h2>
|
||||
<p class="mb-4">The ThreeFold Dashboard gives you all the tools to manage your resources, monitor your nodes, deploy applications, and more - all in one place.</p>
|
||||
|
||||
<div class="d-grid gap-3">
|
||||
<a href="/login" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-box-arrow-in-right me-2"></i> Log In
|
||||
</a>
|
||||
{% if gitea_enabled == false %}
|
||||
<a href="/register" class="btn btn-outline-primary btn-lg">
|
||||
<i class="bi bi-person-plus me-2"></i> Register
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-12">
|
||||
<h2 class="text-center mb-4">What You Can Do in Your Dashboard</h2>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-4 mb-3 text-primary">
|
||||
<i class="bi bi-person"></i>
|
||||
</div>
|
||||
<h5>As a User</h5>
|
||||
<p>Deploy applications, manage slices, monitor costs</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-4 mb-3 text-success">
|
||||
<i class="bi bi-hdd-rack"></i>
|
||||
</div>
|
||||
<h5>As a Farmer</h5>
|
||||
<p>Manage nodes, configure slices, set pricing</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-4 mb-3 text-info">
|
||||
<i class="bi bi-app"></i>
|
||||
</div>
|
||||
<h5>As an App Provider</h5>
|
||||
<p>Offer applications, monitor deployments</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card h-100 border-0 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<div class="display-4 mb-3 text-warning">
|
||||
<i class="bi bi-person-workspace"></i>
|
||||
</div>
|
||||
<h5>As a Service Provider</h5>
|
||||
<p>Offer services, manage maintenance requests</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
363
src/views/docs/3nodes.html
Normal file
363
src/views/docs/3nodes.html
Normal file
@@ -0,0 +1,363 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}3Nodes Documentation - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>3Nodes</h1>
|
||||
<p class="lead">Physical computing hardware that can be bought and sold within the Project Mycelium using USD Credits.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Overview</h2>
|
||||
<p>3Nodes are physical computing hardware (servers, computers) that can be bought and sold within the TF Marketplace using USD Credits. Users can purchase 3Nodes in two distinct ways: either hosted by the supplier or physically transferred to the buyer.</p>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-building me-2 text-primary"></i>Supplier-Hosted</h5>
|
||||
<p class="card-text">Buy the 3Node with upfront Credits payment but have it hosted in the supplier's facility. You maintain ownership while the supplier handles physical maintenance.</p>
|
||||
<p><strong>Ideal for:</strong> Buyers without suitable hosting facilities</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-truck me-2 text-primary"></i>Physical Transfer</h5>
|
||||
<p class="card-text">Buy the 3Node with upfront Credits payment and have it physically shipped to your location. Complete physical control and responsibility for the hardware.</p>
|
||||
<p><strong>Ideal for:</strong> Buyers with their own hosting capabilities</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Core Principles</h2>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-pc-display me-2"></i>Hardware Exchange</h5>
|
||||
<p class="card-text">Direct marketplace for physical computing equipment</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-lock me-2"></i>Sovereignty</h5>
|
||||
<p class="card-text">Buyers gain full ownership of purchased hardware</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-tag me-2"></i>Fair Pricing</h5>
|
||||
<p class="card-text">Market-driven pricing with transparency</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-currency-exchange me-2"></i>Credits-Based</h5>
|
||||
<p class="card-text">All transactions conducted using USD Credits</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-patch-check me-2"></i>Quality Assurance</h5>
|
||||
<p class="card-text">Hardware specifications verified and rated</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-building-up me-2"></i>Flexible Ownership</h5>
|
||||
<p class="card-text">Options for hosted or physically transferred hardware</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>How It Works</h2>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h3 class="mb-0"><i class="bi bi-box-seam me-2"></i>For Sellers</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5>Hardware Registration</h5>
|
||||
<ul>
|
||||
<li>Register available hardware with detailed specifications</li>
|
||||
<li>Upload verification photos and documentation</li>
|
||||
<li>Set pricing in USD Credits</li>
|
||||
<li>Define shipping options and costs</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="mt-4">Listing Management</h5>
|
||||
<ul>
|
||||
<li>Update hardware availability</li>
|
||||
<li>Modify pricing based on market conditions</li>
|
||||
<li>Respond to buyer inquiries</li>
|
||||
<li>Track sales and shipping</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="mb-0"><i class="bi bi-cart-check me-2"></i>For Buyers</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5>Hardware Discovery</h5>
|
||||
<ul>
|
||||
<li>Browse available 3Nodes with filtering options</li>
|
||||
<li>Compare specifications and pricing</li>
|
||||
<li>Review seller ratings and history</li>
|
||||
<li>Ask questions about specific hardware</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="mt-4">Purchase Process</h5>
|
||||
<ul>
|
||||
<li>Select desired 3Node and purchase option (hosted or transferred)</li>
|
||||
<li>Pay upfront using Credits for either option</li>
|
||||
<li>For physical transfer: arrange shipping and delivery</li>
|
||||
<li>For hosted option: receive access credentials</li>
|
||||
<li>Verify functionality and condition</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Hardware Specifications</h2>
|
||||
<p>3Nodes can include various types of computing hardware:</p>
|
||||
|
||||
<div class="row row-cols-1 row-cols-md-2 g-4 mb-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-server me-2"></i>Servers</h5>
|
||||
<p class="card-text">Enterprise-grade rack servers</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-pc me-2"></i>Desktop Computers</h5>
|
||||
<p class="card-text">Repurposed or custom-built desktops</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-cpu me-2"></i>Mini PCs</h5>
|
||||
<p class="card-text">Compact computing devices</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-tools me-2"></i>Custom Builds</h5>
|
||||
<p class="card-text">Purpose-built hardware for TF Grid farming</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Each listing includes detailed specifications:</p>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<ul class="list-group mb-4">
|
||||
<li class="list-group-item"><i class="bi bi-cpu me-2"></i>CPU type and core count</li>
|
||||
<li class="list-group-item"><i class="bi bi-memory me-2"></i>Memory capacity and type</li>
|
||||
<li class="list-group-item"><i class="bi bi-device-ssd me-2"></i>Storage capacity and type</li>
|
||||
<li class="list-group-item"><i class="bi bi-ethernet me-2"></i>Network interfaces</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ul class="list-group mb-4">
|
||||
<li class="list-group-item"><i class="bi bi-lightning me-2"></i>Power consumption</li>
|
||||
<li class="list-group-item"><i class="bi bi-rulers me-2"></i>Physical dimensions</li>
|
||||
<li class="list-group-item"><i class="bi bi-calendar-date me-2"></i>Age and condition</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Credits Exchange Mechanism</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">For Physically Transferred Hardware</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Credits transferred from buyer to seller upon purchase agreement</li>
|
||||
<li>Escrow system protects both parties during shipping</li>
|
||||
<li>Final release upon confirmed delivery and verification</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">For Supplier-Hosted Hardware</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Upfront Credits payment to secure ownership</li>
|
||||
<li>Revenue sharing agreement between buyer and hoster/seller</li>
|
||||
<li>Hoster defines and receives a portion of farming revenue</li>
|
||||
<li>Clear SLAs define uptime and performance guarantees</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Hosting vs. Physical Transfer Comparison</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th>Aspect</th>
|
||||
<th>Supplier-Hosted</th>
|
||||
<th>Physical Transfer</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Physical Location</strong></td>
|
||||
<td>Supplier's facility</td>
|
||||
<td>Buyer's location</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Payment Model</strong></td>
|
||||
<td>Upfront Credits payment</td>
|
||||
<td>Upfront Credits payment</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Revenue Sharing</strong></td>
|
||||
<td>Yes - hoster gets portion of farming revenue</td>
|
||||
<td>No - buyer keeps 100% of farming revenue</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Maintenance</strong></td>
|
||||
<td>Handled by supplier</td>
|
||||
<td>Buyer's responsibility</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Power & Cooling</strong></td>
|
||||
<td>Provided by supplier</td>
|
||||
<td>Buyer's responsibility</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Internet Connectivity</strong></td>
|
||||
<td>Provided by supplier</td>
|
||||
<td>Buyer's responsibility</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Physical Access</strong></td>
|
||||
<td>Limited or none</td>
|
||||
<td>Complete</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Setup Complexity</strong></td>
|
||||
<td>Minimal (handled by supplier)</td>
|
||||
<td>Buyer must set up</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Best For</strong></td>
|
||||
<td>Users without hosting facilities</td>
|
||||
<td>Users with hosting capabilities</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Benefits</h2>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-arrows-angle-contract me-2 text-success"></i>Direct Exchange</h5>
|
||||
<p class="card-text">No intermediaries between hardware sellers and buyers</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-graph-up-arrow me-2 text-success"></i>Ecosystem Growth</h5>
|
||||
<p class="card-text">Facilitates expansion of the TF Grid through hardware redistribution</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-speedometer2 me-2 text-success"></i>Resource Optimization</h5>
|
||||
<p class="card-text">Gives new life to underutilized hardware</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-lock me-2 text-success"></i>Sovereignty</h5>
|
||||
<p class="card-text">Buyers gain full ownership of their hardware, regardless of hosting location</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-arrows-angle-expand me-2 text-success"></i>Flexibility</h5>
|
||||
<p class="card-text">Choose between hosted or physically transferred hardware based on needs</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-people me-2 text-success"></i>Community Building</h5>
|
||||
<p class="card-text">Connects hardware providers with potential farmers</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mt-5">
|
||||
<div class="card-body">
|
||||
<h2><i class="bi bi-question-circle me-2"></i>Ready to Buy or Sell 3Nodes?</h2>
|
||||
<p class="lead">Visit the Project Mycelium 3Nodes section to start exploring options.</p>
|
||||
<div class="mt-3">
|
||||
<a href="/marketplace/3nodes" class="btn btn-primary me-2">Explore 3Nodes Marketplace</a>
|
||||
<a href="/docs" class="btn btn-outline-secondary">Back to Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
539
src/views/docs/api.html
Normal file
539
src/views/docs/api.html
Normal file
@@ -0,0 +1,539 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}API Documentation - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<style>
|
||||
pre.code-block {
|
||||
background-color: #f5f7f9;
|
||||
color: #333;
|
||||
border: 1px solid #e1e4e8;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.code-block code {
|
||||
color: #333;
|
||||
}
|
||||
.code-block .keyword {
|
||||
color: #d73a49;
|
||||
}
|
||||
.code-block .string {
|
||||
color: #032f62;
|
||||
}
|
||||
.code-block .comment {
|
||||
color: #6a737d;
|
||||
font-style: italic;
|
||||
}
|
||||
.code-block .number {
|
||||
color: #005cc5;
|
||||
}
|
||||
</style>
|
||||
<div class="my-4">
|
||||
<h1>Project Mycelium API</h1>
|
||||
<p class="lead">Integrate directly with the Project Mycelium through our REST API.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>API Overview</h2>
|
||||
<p>The Project Mycelium API provides programmatic access to marketplace resources and operations. This allows developers to build applications that interface with the marketplace ecosystem, deploy and manage resources, and perform transactions using USD Credits.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Base URL</h5>
|
||||
<p class="mb-0">All API requests should be directed to <code>https://api.threefold.pro/v1</code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Authentication</h2>
|
||||
<p>The API uses token-based authentication. To obtain an API token:</p>
|
||||
<ol>
|
||||
<li>Log in to your Project Mycelium account</li>
|
||||
<li>Navigate to Settings > API Access</li>
|
||||
<li>Generate a new API token with the required scopes</li>
|
||||
</ol>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">Authentication Example</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<pre class="code-block p-3 rounded"><code><span class="keyword">curl</span> -X <span class="keyword">GET</span> \
|
||||
https://api.threefold.io/v1/resources \
|
||||
-H <span class="string">'Authorization: Bearer YOUR_API_TOKEN'</span></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-shield-lock-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Security Notice</h5>
|
||||
<p class="mb-0">Keep your API tokens secure. Do not expose them in client-side code or public repositories. Tokens have specific permissions based on the scopes you request.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Resource Endpoints</h2>
|
||||
|
||||
<h3>Compute Resources</h3>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Endpoint</th>
|
||||
<th>Method</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>/resources</code></td>
|
||||
<td>GET</td>
|
||||
<td>List available compute resources</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/resources/{id}</code></td>
|
||||
<td>GET</td>
|
||||
<td>Get details about a specific resource</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/resources/search</code></td>
|
||||
<td>POST</td>
|
||||
<td>Search for resources with specific criteria</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/resources/reserve</code></td>
|
||||
<td>POST</td>
|
||||
<td>Reserve a compute resource</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/resources/release/{id}</code></td>
|
||||
<td>POST</td>
|
||||
<td>Release a reserved compute resource</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Deployment</h3>
|
||||
<div class="table-responsive mt-4">
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Endpoint</th>
|
||||
<th>Method</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>/deployments</code></td>
|
||||
<td>GET</td>
|
||||
<td>List all your deployments</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/deployments/{id}</code></td>
|
||||
<td>GET</td>
|
||||
<td>Get details about a specific deployment</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/deployments/create</code></td>
|
||||
<td>POST</td>
|
||||
<td>Create a new deployment</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/deployments/{id}/update</code></td>
|
||||
<td>PUT</td>
|
||||
<td>Update an existing deployment</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/deployments/{id}/delete</code></td>
|
||||
<td>DELETE</td>
|
||||
<td>Delete a deployment</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<h3>Network Nodes</h3>
|
||||
<div class="table-responsive mt-4">
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Endpoint</th>
|
||||
<th>Method</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>/nodes</code></td>
|
||||
<td>GET</td>
|
||||
<td>List all available nodes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/nodes/{id}</code></td>
|
||||
<td>GET</td>
|
||||
<td>Get details about a specific node</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/nodes/mycelium</code></td>
|
||||
<td>GET</td>
|
||||
<td>List all Mycelium nodes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/nodes/super</code></td>
|
||||
<td>GET</td>
|
||||
<td>List all Super nodes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/nodes/register</code></td>
|
||||
<td>POST</td>
|
||||
<td>Register a new node</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Credits Endpoints</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Endpoint</th>
|
||||
<th>Method</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>/credits/balance</code></td>
|
||||
<td>GET</td>
|
||||
<td>Get your Credits balance</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/credits/transactions</code></td>
|
||||
<td>GET</td>
|
||||
<td>List your Credits transactions</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/credits/transfer</code></td>
|
||||
<td>POST</td>
|
||||
<td>Transfer Credits to another account</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/credits/pools</code></td>
|
||||
<td>GET</td>
|
||||
<td>Get information about available liquidity pools</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/credits/pools/exchange</code></td>
|
||||
<td>POST</td>
|
||||
<td>Exchange between Credits and other currencies/tokens</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/credits/stake</code></td>
|
||||
<td>POST</td>
|
||||
<td>Stake Credits</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>API Response Format</h2>
|
||||
<p>All API responses are returned in JSON format. A typical response includes:</p>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">Response Structure</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<pre class="code-block p-3 rounded"><code>{
|
||||
<span class="string">"status"</span>: <span class="string">"success"</span>, <span class="comment">// or "error"</span>
|
||||
<span class="string">"data"</span>: {
|
||||
<span class="comment">// Response data specific to the endpoint</span>
|
||||
},
|
||||
<span class="string">"meta"</span>: {
|
||||
<span class="string">"page"</span>: <span class="number">1</span>,
|
||||
<span class="string">"limit"</span>: <span class="number">20</span>,
|
||||
<span class="string">"total"</span>: <span class="number">42</span>
|
||||
<span class="comment">// Additional metadata as needed</span>
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Error Handling</h3>
|
||||
<p>When an error occurs, the API will return an appropriate HTTP status code and an error message:</p>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">Error Response</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<pre class="code-block p-3 rounded"><code>{
|
||||
<span class="string">"status"</span>: <span class="string">"error"</span>,
|
||||
<span class="string">"error"</span>: {
|
||||
<span class="string">"code"</span>: <span class="string">"insufficient_credits"</span>,
|
||||
<span class="string">"message"</span>: <span class="string">"Insufficient Credits balance for this operation"</span>,
|
||||
<span class="string">"details"</span>: {
|
||||
<span class="string">"required"</span>: <span class="number">100</span>,
|
||||
<span class="string">"available"</span>: <span class="number">75</span>
|
||||
}
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Rate Limiting</h2>
|
||||
<p>To ensure fair usage of the API, rate limits are applied:</p>
|
||||
<ul>
|
||||
<li>Standard accounts: 60 requests per minute</li>
|
||||
<li>Premium accounts: 300 requests per minute</li>
|
||||
</ul>
|
||||
<p>Rate limit information is included in the response headers:</p>
|
||||
<ul>
|
||||
<li><code>X-RateLimit-Limit</code>: Maximum requests per minute</li>
|
||||
<li><code>X-RateLimit-Remaining</code>: Remaining requests in current period</li>
|
||||
<li><code>X-RateLimit-Reset</code>: Time when the rate limit resets (Unix timestamp)</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Sample Code</h2>
|
||||
|
||||
<ul class="nav nav-tabs mb-3" id="codeExampleTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="nodejs-tab" data-bs-toggle="tab" data-bs-target="#nodejs" type="button" role="tab" aria-controls="nodejs" aria-selected="true">Node.js</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="python-tab" data-bs-toggle="tab" data-bs-target="#python" type="button" role="tab" aria-controls="python" aria-selected="false">Python</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="curl-tab" data-bs-toggle="tab" data-bs-target="#curl" type="button" role="tab" aria-controls="curl" aria-selected="false">cURL</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="codeExampleTabsContent">
|
||||
<div class="tab-pane fade show active" id="nodejs" role="tabpanel" aria-labelledby="nodejs-tab">
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">Node.js Example: Deploy an Application</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<pre class="code-block p-3 rounded"><code><span class="keyword">const</span> axios = <span class="keyword">require</span>(<span class="string">'axios'</span>);
|
||||
|
||||
<span class="keyword">const</span> API_TOKEN = <span class="string">'your_api_token'</span>;
|
||||
<span class="keyword">const</span> BASE_URL = <span class="string">'https://api.threefold.pro/v1'</span>;
|
||||
|
||||
<span class="keyword">async function</span> <span class="keyword">deployApplication</span>() {
|
||||
<span class="keyword">try</span> {
|
||||
<span class="comment">// 1. Find available resources</span>
|
||||
<span class="keyword">const</span> resourceResponse = <span class="keyword">await</span> axios.post(`${BASE_URL}/resources/search`, {
|
||||
cpu_cores: <span class="number">4</span>,
|
||||
memory_mb: <span class="number">8192</span>,
|
||||
disk_gb: <span class="number">100</span>,
|
||||
location: <span class="string">'europe'</span>
|
||||
}, {
|
||||
headers: {
|
||||
<span class="string">'Authorization'</span>: `Bearer ${API_TOKEN}`,
|
||||
<span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>
|
||||
}
|
||||
});
|
||||
|
||||
<span class="keyword">const</span> resourceId = resourceResponse.data.data[<span class="number">0</span>].id;
|
||||
|
||||
<span class="comment">// 2. Reserve the resource</span>
|
||||
<span class="keyword">await</span> axios.post(`${BASE_URL}/resources/reserve`, {
|
||||
resource_id: resourceId,
|
||||
duration_hours: <span class="number">720</span> <span class="comment">// 30 days</span>
|
||||
}, {
|
||||
headers: {
|
||||
<span class="string">'Authorization'</span>: `Bearer ${API_TOKEN}`,
|
||||
<span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>
|
||||
}
|
||||
});
|
||||
|
||||
<span class="comment">// 3. Deploy application</span>
|
||||
<span class="keyword">const</span> deploymentResponse = <span class="keyword">await</span> axios.post(`${BASE_URL}/deployments/create`, {
|
||||
name: <span class="string">'My Web Application'</span>,
|
||||
resource_id: resourceId,
|
||||
specs: {
|
||||
image: <span class="string">'nginx:latest'</span>,
|
||||
ports: [<span class="number">80</span>],
|
||||
environment: {
|
||||
<span class="string">'NGINX_HOST'</span>: <span class="string">'example.org'</span>
|
||||
}
|
||||
}
|
||||
}, {
|
||||
headers: {
|
||||
<span class="string">'Authorization'</span>: `Bearer ${API_TOKEN}`,
|
||||
<span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>
|
||||
}
|
||||
});
|
||||
|
||||
console.log(<span class="string">'Deployment successful!'</span>, deploymentResponse.data);
|
||||
|
||||
} <span class="keyword">catch</span> (error) {
|
||||
console.error(<span class="string">'Deployment failed:'</span>, error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
deployApplication();</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="python" role="tabpanel" aria-labelledby="python-tab">
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">Python Example: Deploy an Application</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<pre class="code-block p-3 rounded"><code><span class="keyword">import</span> requests
|
||||
|
||||
API_TOKEN = <span class="string">'your_api_token'</span>
|
||||
BASE_URL = <span class="string">'https://api.threefold.pro/v1'</span>
|
||||
|
||||
<span class="keyword">def</span> <span class="keyword">deploy_application</span>():
|
||||
headers = {
|
||||
<span class="string">'Authorization'</span>: <span class="string">f'Bearer {API_TOKEN}'</span>,
|
||||
<span class="string">'Content-Type'</span>: <span class="string">'application/json'</span>
|
||||
}
|
||||
|
||||
<span class="keyword">try</span>:
|
||||
<span class="comment"># 1. Find available resources</span>
|
||||
resource_response = requests.post(
|
||||
<span class="string">f'{BASE_URL}/resources/search'</span>,
|
||||
json={
|
||||
<span class="string">'cpu_cores'</span>: <span class="number">4</span>,
|
||||
<span class="string">'memory_mb'</span>: <span class="number">8192</span>,
|
||||
<span class="string">'disk_gb'</span>: <span class="number">100</span>,
|
||||
<span class="string">'location'</span>: <span class="string">'europe'</span>
|
||||
},
|
||||
headers=headers
|
||||
)
|
||||
resource_response.raise_for_status()
|
||||
|
||||
resource_id = resource_response.json()[<span class="string">'data'</span>][<span class="number">0</span>][<span class="string">'id'</span>]
|
||||
|
||||
<span class="comment"># 2. Reserve the resource</span>
|
||||
reserve_response = requests.post(
|
||||
<span class="string">f'{BASE_URL}/resources/reserve'</span>,
|
||||
json={
|
||||
<span class="string">'resource_id'</span>: resource_id,
|
||||
<span class="string">'duration_hours'</span>: <span class="number">720</span> <span class="comment"># 30 days</span>
|
||||
},
|
||||
headers=headers
|
||||
)
|
||||
reserve_response.raise_for_status()
|
||||
|
||||
<span class="comment"># 3. Deploy application</span>
|
||||
deployment_response = requests.post(
|
||||
<span class="string">f'{BASE_URL}/deployments/create'</span>,
|
||||
json={
|
||||
<span class="string">'name'</span>: <span class="string">'My Web Application'</span>,
|
||||
<span class="string">'resource_id'</span>: resource_id,
|
||||
<span class="string">'specs'</span>: {
|
||||
<span class="string">'image'</span>: <span class="string">'nginx:latest'</span>,
|
||||
<span class="string">'ports'</span>: [<span class="number">80</span>],
|
||||
<span class="string">'environment'</span>: {
|
||||
<span class="string">'NGINX_HOST'</span>: <span class="string">'example.org'</span>
|
||||
}
|
||||
}
|
||||
},
|
||||
headers=headers
|
||||
)
|
||||
deployment_response.raise_for_status()
|
||||
|
||||
print(<span class="string">'Deployment successful!'</span>, deployment_response.json())
|
||||
|
||||
<span class="keyword">except</span> requests.exceptions.RequestException <span class="keyword">as</span> e:
|
||||
print(<span class="string">f'Deployment failed: {e}'</span>)
|
||||
<span class="keyword">if</span> hasattr(e, <span class="string">'response'</span>) <span class="keyword">and</span> e.response:
|
||||
print(e.response.json())
|
||||
|
||||
<span class="keyword">if</span> __name__ == <span class="string">'__main__'</span>:
|
||||
deploy_application()</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="curl" role="tabpanel" aria-labelledby="curl-tab">
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">cURL Example: Deploy an Application</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<pre class="code-block p-3 rounded"><code><span class="comment"># 1. Find available resources</span>
|
||||
<span class="keyword">curl</span> -X <span class="keyword">POST</span> \
|
||||
https://api.threefold.pro/v1/resources/search \
|
||||
-H <span class="string">'Authorization: Bearer YOUR_API_TOKEN'</span> \
|
||||
-H <span class="string">'Content-Type: application/json'</span> \
|
||||
-d <span class="string">'{
|
||||
"cpu_cores": 4,
|
||||
"memory_mb": 8192,
|
||||
"disk_gb": 100,
|
||||
"location": "europe"
|
||||
}'</span>
|
||||
|
||||
<span class="comment"># 2. Reserve the resource (replace RESOURCE_ID with actual ID from previous response)</span>
|
||||
<span class="keyword">curl</span> -X <span class="keyword">POST</span> \
|
||||
https://api.threefold.pro/v1/resources/reserve \
|
||||
-H <span class="string">'Authorization: Bearer YOUR_API_TOKEN'</span> \
|
||||
-H <span class="string">'Content-Type: application/json'</span> \
|
||||
-d <span class="string">'{
|
||||
"resource_id": "RESOURCE_ID",
|
||||
"duration_hours": 720
|
||||
}'</span>
|
||||
|
||||
<span class="comment"># 3. Deploy application</span>
|
||||
<span class="keyword">curl</span> -X <span class="keyword">POST</span> \
|
||||
https://api.threefold.pro/v1/deployments/create \
|
||||
-H <span class="string">'Authorization: Bearer YOUR_API_TOKEN'</span> \
|
||||
-H <span class="string">'Content-Type: application/json'</span> \
|
||||
-d <span class="string">'{
|
||||
"name": "My Web Application",
|
||||
"resource_id": "RESOURCE_ID",
|
||||
"specs": {
|
||||
"image": "nginx:latest",
|
||||
"ports": [80],
|
||||
"environment": {
|
||||
"NGINX_HOST": "example.org"
|
||||
}
|
||||
}
|
||||
}'</span></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-secondary mt-5">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-tools fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Need More Help?</h5>
|
||||
<p class="mb-0">For additional support or to report API issues, please contact our developer support team at <a href="mailto:api-support@threefold.pro">api-support@threefold.pro</a> or visit our <a href="https://github.com/threefoldtech/api-docs" target="_blank">GitHub repository</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
389
src/views/docs/applications.html
Normal file
389
src/views/docs/applications.html
Normal file
@@ -0,0 +1,389 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}Application Solutions - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>Application Solutions</h1>
|
||||
<p class="lead">Discover self-healing applications that maintain sovereignty while offering convenience.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Overview</h2>
|
||||
<p>ThreeFold Application Solutions represent a new approach to application deployment that balances ease of use with digital sovereignty. These pre-configured, self-healing applications are designed to run on the ThreeFold Grid while allowing users to maintain complete control over their infrastructure and data.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">The ThreeFold Difference</h5>
|
||||
<p class="mb-0">Unlike traditional SaaS offerings that require surrendering control of your data to the provider, ThreeFold Application Solutions run on compute resources that remain under your sovereign control, while the solution provider manages only the application layer.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Application Categories</h2>
|
||||
<p>The Project Mycelium offers a diverse range of application solutions across multiple categories:</p>
|
||||
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-people me-2 text-primary"></i>Collaboration</h5>
|
||||
<p class="card-text">Tools for team communication, document sharing, and real-time collaboration.</p>
|
||||
<p class="small text-muted">Examples: Office suites, project management, video conferencing</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-window me-2 text-primary"></i>Productivity</h5>
|
||||
<p class="card-text">Applications to enhance personal and team productivity and workflow management.</p>
|
||||
<p class="small text-muted">Examples: CRM systems, task management, time tracking</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-code-square me-2 text-primary"></i>Development</h5>
|
||||
<p class="card-text">Tools and environments for software development and DevOps practices.</p>
|
||||
<p class="small text-muted">Examples: Code repositories, CI/CD pipelines, development environments</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-database me-2 text-primary"></i>Database</h5>
|
||||
<p class="card-text">Managed database solutions with high availability and performance optimization.</p>
|
||||
<p class="small text-muted">Examples: SQL/NoSQL databases, time-series databases, analytics engines</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-chat-left-text me-2 text-primary"></i>Communication</h5>
|
||||
<p class="card-text">Secure messaging, email, and communication platforms with privacy by design.</p>
|
||||
<p class="small text-muted">Examples: Email servers, chat platforms, video conferencing</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-layout-text-window me-2 text-primary"></i>Content Management</h5>
|
||||
<p class="card-text">Systems for creating, managing, and publishing digital content.</p>
|
||||
<p class="small text-muted">Examples: WordPress, wikis, document management</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>How It Works</h2>
|
||||
<p>Application Solutions on the Project Mycelium function through a unique partnership model between users and solution providers:</p>
|
||||
|
||||
<div class="row align-items-center mb-4">
|
||||
<div class="col-md-6">
|
||||
<img src="/static/images/docs/application-flow.svg" alt="Application Solution Flow Diagram" class="img-fluid rounded shadow">
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<ol class="list-group list-group-numbered mb-0">
|
||||
<li class="list-group-item d-flex">
|
||||
<div>
|
||||
<strong>Resource Provision</strong>
|
||||
<p class="mb-0 text-muted">You allocate compute slices from your ThreeFold account to run the application.</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div>
|
||||
<strong>Solution Deployment</strong>
|
||||
<p class="mb-0 text-muted">The solution provider deploys their application on your sovereign compute resources.</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div>
|
||||
<strong>Application Management</strong>
|
||||
<p class="mb-0 text-muted">The provider handles updates, maintenance, and ensures the application remains operational.</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex">
|
||||
<div>
|
||||
<strong>Payment Model</strong>
|
||||
<p class="mb-0 text-muted">You pay the solution provider in USD Credits based on the agreed-upon pricing model.</p>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-shield-check fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Sovereignty Maintained</h5>
|
||||
<p class="mb-0">Your data and applications remain on infrastructure under your control. The solution provider cannot access your data without your explicit permission, and you can revoke their management access at any time.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Self-Healing Architecture</h2>
|
||||
<p>All applications in the Project Mycelium feature self-healing capabilities to ensure reliability and minimal downtime:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<i class="bi bi-heart-pulse fs-3 text-danger"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Continuous Monitoring</h5>
|
||||
<p>Real-time health checks and performance metrics collection to detect issues before they affect your operations.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<i class="bi bi-arrow-repeat fs-3 text-warning"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Automated Recovery</h5>
|
||||
<p>Systems automatically detect failures and initiate recovery procedures like service restarts or container recreation.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<i class="bi bi-clock-history fs-3 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Backup Systems</h5>
|
||||
<p>Regular automated backups with verification and point-in-time recovery capabilities to prevent data loss.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<i class="bi bi-shield-check fs-3 text-success"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Security Updates</h5>
|
||||
<p>Automatic security patches and updates to protect against vulnerabilities and maintain system integrity.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Solution Provider Certification</h2>
|
||||
<p>Solution providers in the Project Mycelium undergo a certification process to ensure quality and reliability:</p>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th>Certification Level</th>
|
||||
<th>Requirements</th>
|
||||
<th>Benefits</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><span class="badge bg-success">Certified</span></td>
|
||||
<td>
|
||||
<ul class="mb-0">
|
||||
<li>Rigorous technical review</li>
|
||||
<li>Security audits</li>
|
||||
<li>SLA commitments</li>
|
||||
<li>Customer support standards</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul class="mb-0">
|
||||
<li>Featured placement in marketplace</li>
|
||||
<li>Higher trust rating</li>
|
||||
<li>Extended support options</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="badge bg-warning">Community</span></td>
|
||||
<td>
|
||||
<ul class="mb-0">
|
||||
<li>Basic technical verification</li>
|
||||
<li>Community-reviewed</li>
|
||||
<li>Documentation standards</li>
|
||||
<li>Transparent operations</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul class="mb-0">
|
||||
<li>Standard marketplace listing</li>
|
||||
<li>Community support options</li>
|
||||
<li>Path to certification</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Deployment Process</h2>
|
||||
<p>Deploying an application from the Project Mycelium is a straightforward process:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-shop fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">1. Select Application</h5>
|
||||
<p class="card-text">Browse the marketplace and select your desired application solution.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-gear fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">2. Configure Options</h5>
|
||||
<p class="card-text">Choose deployment options, resource levels, and customize settings.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-cpu fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">3. Allocate Resources</h5>
|
||||
<p class="card-text">Assign compute slices to run the application from your account.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-check-circle fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">4. Deploy & Access</h5>
|
||||
<p class="card-text">Complete deployment and receive access credentials.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Resource Requirements</h2>
|
||||
<p>Different applications have varying resource requirements based on their complexity and functionality:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0">Light</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-cpu me-2"></i>
|
||||
<div>1-2 vCPUs</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-memory me-2"></i>
|
||||
<div>2-4 GB RAM</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-hdd me-2"></i>
|
||||
<div>10-20 GB Storage</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="text-muted mb-0">Suitable for personal blogs, simple websites, and lightweight applications.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-warning text-white">
|
||||
<h5 class="mb-0">Medium</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-cpu me-2"></i>
|
||||
<div>2-4 vCPUs</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-memory me-2"></i>
|
||||
<div>4-8 GB RAM</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-hdd me-2"></i>
|
||||
<div>20-50 GB Storage</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="text-muted mb-0">Ideal for team collaboration tools, content management systems, and small business applications.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-danger text-white">
|
||||
<h5 class="mb-0">Heavy</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-cpu me-2"></i>
|
||||
<div>4+ vCPUs</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-memory me-2"></i>
|
||||
<div>8+ GB RAM</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-hdd me-2"></i>
|
||||
<div>50+ GB Storage</div>
|
||||
</div>
|
||||
<hr>
|
||||
<p class="text-muted mb-0">Required for databases, enterprise applications, and resource-intensive workloads.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mt-5">
|
||||
<div class="card-body">
|
||||
<h2><i class="bi bi-app-indicator me-2"></i>Ready to Deploy Applications?</h2>
|
||||
<p class="lead">Browse our collection of sovereign applications and find the perfect solution for your needs.</p>
|
||||
<div class="mt-3">
|
||||
<a href="/marketplace/applications" class="btn btn-primary me-2">Explore Applications</a>
|
||||
<a href="/docs" class="btn btn-outline-secondary">Back to Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
497
src/views/docs/certification.html
Normal file
497
src/views/docs/certification.html
Normal file
@@ -0,0 +1,497 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}Certification - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>Certification</h1>
|
||||
<p class="lead">Understanding the quality assurance and trust framework in the ThreeFold ecosystem.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Overview</h2>
|
||||
<p>The ThreeFold Certification framework establishes trust and quality standards throughout the ecosystem. This multi-layered certification system applies to hardware, software, and service providers, ensuring reliability, security, and compatibility across the ThreeFold Grid and Marketplace.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Key Concept</h5>
|
||||
<p class="mb-0">Certification in the ThreeFold ecosystem is designed to build trust in a decentralized network where participants may not know each other directly. Through transparent verification processes and clear standards, certification provides assurance of quality, security, and compatibility.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Certification Types</h2>
|
||||
<p>The ThreeFold ecosystem incorporates several types of certification tailored to different components:</p>
|
||||
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-hdd-rack me-2 text-primary"></i>Hardware Certification</h5>
|
||||
<p class="card-text">Verification of 3Nodes and physical infrastructure components to ensure they meet performance, reliability, and security standards.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-window me-2 text-primary"></i>Application Certification</h5>
|
||||
<p class="card-text">Validation of software applications in the marketplace to confirm security, performance, and compatibility with ThreeFold infrastructure.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-person-badge me-2 text-primary"></i>Provider Certification</h5>
|
||||
<p class="card-text">Verification of service providers' expertise, reliability, and adherence to ThreeFold standards and best practices.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-check me-2 text-primary"></i>Security Certification</h5>
|
||||
<p class="card-text">Specific assessment of security measures, vulnerabilities, and protection capabilities across all ecosystem components.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-speedometer2 me-2 text-primary"></i>Performance Certification</h5>
|
||||
<p class="card-text">Benchmarking and validation of performance metrics, ensuring resources deliver their stated capabilities.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-geo-alt me-2 text-primary"></i>Geographic Certification</h5>
|
||||
<p class="card-text">Verification of physical location and regulatory compliance according to regional requirements.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Certification Levels</h2>
|
||||
<p>The ThreeFold ecosystem uses tiered certification levels to indicate different standards of verification:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-warning text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-award me-2"></i>Community Level</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Basic verification with community oversight</strong></p>
|
||||
<ul>
|
||||
<li><strong>Verification Process:</strong> Self-reported specifications with community review</li>
|
||||
<li><strong>Quality Assurance:</strong> Minimal standardized testing</li>
|
||||
<li><strong>Security Requirements:</strong> Basic security checklist</li>
|
||||
<li><strong>Monitoring:</strong> Limited performance tracking</li>
|
||||
<li><strong>Trust Level:</strong> Entry-level, suitable for non-critical workloads</li>
|
||||
</ul>
|
||||
<div class="text-center mt-3">
|
||||
<span class="badge bg-warning rounded-pill px-4 py-2">COMMUNITY</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-patch-check me-2"></i>Verified Level</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Thorough verification with tested performance</strong></p>
|
||||
<ul>
|
||||
<li><strong>Verification Process:</strong> Third-party validation of specifications</li>
|
||||
<li><strong>Quality Assurance:</strong> Comprehensive standardized testing</li>
|
||||
<li><strong>Security Requirements:</strong> Enhanced security protocols</li>
|
||||
<li><strong>Monitoring:</strong> Regular performance validation</li>
|
||||
<li><strong>Trust Level:</strong> Medium, suitable for standard production workloads</li>
|
||||
</ul>
|
||||
<div class="text-center mt-3">
|
||||
<span class="badge bg-success rounded-pill px-4 py-2">VERIFIED</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-shield-fill-check me-2"></i>Certified Level</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Premium verification with guaranteed performance</strong></p>
|
||||
<ul>
|
||||
<li><strong>Verification Process:</strong> Rigorous independent certification</li>
|
||||
<li><strong>Quality Assurance:</strong> Extensive testing under varied conditions</li>
|
||||
<li><strong>Security Requirements:</strong> Advanced security measures with audits</li>
|
||||
<li><strong>Monitoring:</strong> Continuous monitoring with SLA guarantees</li>
|
||||
<li><strong>Trust Level:</strong> High, suitable for enterprise and critical workloads</li>
|
||||
</ul>
|
||||
<div class="text-center mt-3">
|
||||
<span class="badge bg-primary rounded-pill px-4 py-2">CERTIFIED</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Certification Process</h2>
|
||||
<p>The journey to achieve certification involves several structured stages:</p>
|
||||
|
||||
<div class="position-relative mb-5 mt-4">
|
||||
<div class="progress" style="height: 3px;">
|
||||
<div class="progress-bar bg-primary" role="progressbar" style="width: 100%;" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="row text-center mt-4">
|
||||
<div class="col">
|
||||
<div class="position-absolute" style="top: -15px; left: 0%;">
|
||||
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center" style="width: 35px; height: 35px;">1</div>
|
||||
</div>
|
||||
<h6 class="mt-4">Application</h6>
|
||||
<p class="small text-muted">Submission of certification request with required specifications and documentation</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="position-absolute" style="top: -15px; left: 25%;">
|
||||
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center" style="width: 35px; height: 35px;">2</div>
|
||||
</div>
|
||||
<h6 class="mt-4">Initial Review</h6>
|
||||
<p class="small text-muted">Document verification and preliminary assessment</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="position-absolute" style="top: -15px; left: 50%;">
|
||||
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center" style="width: 35px; height: 35px;">3</div>
|
||||
</div>
|
||||
<h6 class="mt-4">Testing</h6>
|
||||
<p class="small text-muted">Technical evaluation, benchmarking, and security assessment</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="position-absolute" style="top: -15px; left: 75%;">
|
||||
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center" style="width: 35px; height: 35px;">4</div>
|
||||
</div>
|
||||
<h6 class="mt-4">Decision</h6>
|
||||
<p class="small text-muted">Certification determination based on test results</p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="position-absolute" style="top: -15px; left: 100%; margin-left: -17px;">
|
||||
<div class="rounded-circle bg-primary text-white d-flex align-items-center justify-content-center" style="width: 35px; height: 35px;">5</div>
|
||||
</div>
|
||||
<h6 class="mt-4">Monitoring</h6>
|
||||
<p class="small text-muted">Ongoing validation to maintain certification status</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-light border">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-clock-fill fs-3 text-secondary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Certification Timeline</h5>
|
||||
<p>The certification process typically takes:</p>
|
||||
<ul>
|
||||
<li><strong>Community Level:</strong> 1-3 days (streamlined process)</li>
|
||||
<li><strong>Verified Level:</strong> 1-2 weeks (standard process)</li>
|
||||
<li><strong>Certified Level:</strong> 2-4 weeks (comprehensive process)</li>
|
||||
</ul>
|
||||
<p class="mb-0">Timelines may vary based on complexity and responsiveness during the review process.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Certification Standards</h2>
|
||||
<p>ThreeFold certification standards are designed to ensure consistent quality across the ecosystem:</p>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th>Domain</th>
|
||||
<th>Key Standards</th>
|
||||
<th>Validation Methods</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Performance</strong></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Resource delivery accuracy</li>
|
||||
<li>Throughput guarantees</li>
|
||||
<li>Response time metrics</li>
|
||||
<li>Scaling capabilities</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Standardized benchmark suites</li>
|
||||
<li>Load testing</li>
|
||||
<li>Long-duration performance monitoring</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Security</strong></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Zero-OS implementation</li>
|
||||
<li>Encryption standards</li>
|
||||
<li>Vulnerability management</li>
|
||||
<li>Identity and access controls</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Penetration testing</li>
|
||||
<li>Security audits</li>
|
||||
<li>Code reviews</li>
|
||||
<li>Compliance verification</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Reliability</strong></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Uptime guarantees</li>
|
||||
<li>Fault tolerance</li>
|
||||
<li>Data durability</li>
|
||||
<li>Disaster recovery capabilities</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Chaos engineering tests</li>
|
||||
<li>Simulated failures</li>
|
||||
<li>Historical reliability data analysis</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Compatibility</strong></td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Grid protocol conformance</li>
|
||||
<li>API standards adherence</li>
|
||||
<li>Interoperability requirements</li>
|
||||
<li>Integration capabilities</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<ul>
|
||||
<li>Integration testing</li>
|
||||
<li>Protocol validation</li>
|
||||
<li>Compatibility matrices</li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Benefits of Certification</h2>
|
||||
<p>Certification provides substantial advantages to all participants in the ThreeFold ecosystem:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<h5 class="mb-3"><i class="bi bi-shop me-2 text-success"></i>For Providers</h5>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><strong>Enhanced Visibility:</strong> Certified offerings receive priority placement in marketplace listings</li>
|
||||
<li><strong>Premium Pricing:</strong> Ability to command higher rates based on certified quality</li>
|
||||
<li><strong>Trust Building:</strong> Official recognition of quality and reliability</li>
|
||||
<li><strong>Access to Enterprise Markets:</strong> Eligibility for enterprise-level clients with certification requirements</li>
|
||||
<li><strong>Quality Feedback:</strong> Detailed assessment information to improve offerings</li>
|
||||
<li><strong>Marketing Benefits:</strong> Permission to use certification badges in marketing materials</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h5 class="mb-3"><i class="bi bi-person me-2 text-primary"></i>For Consumers</h5>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><strong>Quality Assurance:</strong> Confidence in certified resources and services</li>
|
||||
<li><strong>Risk Reduction:</strong> Lower likelihood of issues with verified offerings</li>
|
||||
<li><strong>Performance Guarantees:</strong> Certified offerings come with explicit SLAs</li>
|
||||
<li><strong>Simplified Selection:</strong> Certification levels help with decision-making</li>
|
||||
<li><strong>Compliance Support:</strong> Certified options may help meet regulatory requirements</li>
|
||||
<li><strong>Support Guarantees:</strong> Higher certification levels include enhanced support</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h5 class="mb-3"><i class="bi bi-globe2 me-2 text-info"></i>For the Ecosystem</h5>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<ul>
|
||||
<li><strong>Quality Standards:</strong> Elevated baseline for all participants</li>
|
||||
<li><strong>Network Reliability:</strong> More stable and dependable infrastructure</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<ul>
|
||||
<li><strong>Trust Framework:</strong> Reinforced trust in a decentralized environment</li>
|
||||
<li><strong>Growth Acceleration:</strong> Faster adoption through established trust</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<ul>
|
||||
<li><strong>Security Enhancement:</strong> Higher overall security posture</li>
|
||||
<li><strong>Reduced Conflicts:</strong> Clear standards minimize disagreements</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Certification Authorities</h2>
|
||||
<p>The ThreeFold certification system involves multiple layers of validation:</p>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card h-100 text-center">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-people-fill fs-1 text-warning"></i>
|
||||
</div>
|
||||
<h5 class="card-title">Community Review</h5>
|
||||
<p class="card-text">Collective assessment by community members for basic certification</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card h-100 text-center">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-shield-fill fs-1 text-success"></i>
|
||||
</div>
|
||||
<h5 class="card-title">ThreeFold Teams</h5>
|
||||
<p class="card-text">Core teams responsible for standard verification processes</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card h-100 text-center">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-building fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">Independent Validators</h5>
|
||||
<p class="card-text">Third-party experts who perform specialized assessments</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card h-100 text-center">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-code-slash fs-1 text-info"></i>
|
||||
</div>
|
||||
<h5 class="card-title">Automated Systems</h5>
|
||||
<p class="card-text">AI-powered testing and validation for continuous monitoring</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-secondary mt-4">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-diagram-3-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Decentralized Certification</h5>
|
||||
<p class="mb-0">The ThreeFold certification system is designed to be increasingly decentralized over time. The ultimate goal is to create a self-sustaining network of independent certifiers who maintain the quality standards of the ecosystem while preventing centralized control.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Certification Verification</h2>
|
||||
<p>Certification status can be verified through several methods:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-search me-2 text-secondary"></i>Public Registry</h5>
|
||||
<p>All certified entities are listed in a public, searchable registry with detailed certification information.</p>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">Access Registry</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-qr-code me-2 text-secondary"></i>Verification Codes</h5>
|
||||
<p>Each certified entity receives a unique verification code that can be validated through the ThreeFold platform.</p>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">Verify Code</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-file-earmark-text me-2 text-secondary"></i>Certification Reports</h5>
|
||||
<p>Detailed certification reports are available for review, showing test results and compliance details.</p>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">View Sample Report</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center bg-light p-3 rounded">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-lightbulb-fill fs-3 text-warning"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Pro Tip</h5>
|
||||
<p class="mb-0">When evaluating marketplace offerings, look for the certification badges displayed on listings. These badges are clickable and will take you directly to the verification page for that specific item.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mt-5">
|
||||
<div class="card-body">
|
||||
<h2><i class="bi bi-award me-2"></i>Ready to Get Certified?</h2>
|
||||
<p class="lead">If you're a provider looking to certify your resources or services, start the certification process today.</p>
|
||||
<div class="mt-3">
|
||||
<a href="/dashboard" class="btn btn-primary me-2">Start Certification Process</a>
|
||||
<a href="/docs" class="btn btn-outline-secondary">Back to Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
259
src/views/docs/compute.html
Normal file
259
src/views/docs/compute.html
Normal file
@@ -0,0 +1,259 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}Compute Resources - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>Compute Resources (Slices)</h1>
|
||||
<p class="lead">Understanding the core compute resources available in the Project Mycelium.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Overview</h2>
|
||||
<p>Compute Resources, often referred to as "Slices," are the fundamental units of computing capacity in the ThreeFold ecosystem. They represent virtualized portions of underlying physical hardware (3Nodes) that can be used to deploy workloads, applications, and services.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Key Concept</h5>
|
||||
<p class="mb-0">Unlike traditional cloud computing models, ThreeFold's compute resources are fully sovereign, meaning you maintain complete control and ownership over your resources and the workloads deployed on them.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Resource Components</h2>
|
||||
<p>Each compute slice consists of a combination of the following resources:</p>
|
||||
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-cpu me-2 text-primary"></i>Compute (vCPU)</h5>
|
||||
<p class="card-text">Virtual CPU cores allocated for processing power, measured in cores or units.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-memory me-2 text-primary"></i>Memory (RAM)</h5>
|
||||
<p class="card-text">Random Access Memory for temporary data storage and active computations, measured in GB.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-device-ssd me-2 text-primary"></i>Storage</h5>
|
||||
<p class="card-text">Persistent storage for data, available in SSD (fast) or HDD (high-capacity) options, measured in GB.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-ethernet me-2 text-primary"></i>Network</h5>
|
||||
<p class="card-text">Bandwidth allocation for data transfer between your resources and the internet, measured in GB transferred.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-globe me-2 text-primary"></i>Public IPv4</h5>
|
||||
<p class="card-text">Optional public IP addresses for direct internet accessibility.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-lock me-2 text-primary"></i>Zero-OS</h5>
|
||||
<p class="card-text">The secure, minimalist operating system that powers each compute slice.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Resource Tiers</h2>
|
||||
<p>Compute resources are available in different tiers to suit various workload requirements:</p>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th>Tier</th>
|
||||
<th>Description</th>
|
||||
<th>Ideal For</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Basic</strong></td>
|
||||
<td>Entry-level resources with balanced specifications</td>
|
||||
<td>Development environments, testing, personal projects</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Standard</strong></td>
|
||||
<td>Mid-range resources suitable for most applications</td>
|
||||
<td>Production websites, small databases, containerized applications</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Professional</strong></td>
|
||||
<td>High-performance resources with enhanced capabilities</td>
|
||||
<td>Business applications, medium databases, compute-intensive tasks</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Enterprise</strong></td>
|
||||
<td>Premium resources with maximum performance</td>
|
||||
<td>Large databases, high-traffic applications, distributed systems</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Deployment Options</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-box me-2 text-success"></i>Virtual Machines</h5>
|
||||
<p class="card-text">Deploy full virtual machines with your choice of operating system and complete control over the environment.</p>
|
||||
<ul>
|
||||
<li>Support for most Linux distributions</li>
|
||||
<li>Full isolation and security</li>
|
||||
<li>Complete access and control</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-layers me-2 text-success"></i>Containers</h5>
|
||||
<p class="card-text">Deploy lightweight, portable container workloads for efficient resource utilization.</p>
|
||||
<ul>
|
||||
<li>Docker-compatible container runtime</li>
|
||||
<li>Kubernetes support</li>
|
||||
<li>Rapid deployment and scaling</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Credits Exchange Mechanism</h2>
|
||||
<p>Compute resources are exchanged through the USD Credits value exchange system:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">For Consumers</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Pay Credits based on resource specifications and usage duration</li>
|
||||
<li>Choose between prepaid or pay-as-you-go billing models</li>
|
||||
<li>Receive detailed usage reports and billing transparency</li>
|
||||
<li>Maintain sovereignty over deployed workloads</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">For Providers</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li>Receive Credits for resources consumed by users</li>
|
||||
<li>Automatic payments based on verified resource utilization</li>
|
||||
<li>Set pricing within market-driven parameters</li>
|
||||
<li>Build reputation through consistent service delivery</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Resource Management</h2>
|
||||
<p>The Project Mycelium provides comprehensive tools for managing your compute resources:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-display me-2 text-secondary"></i>Dashboard</h5>
|
||||
<p>Monitor resource usage, performance metrics, and billing information through the intuitive dashboard.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-sliders me-2 text-secondary"></i>Scaling</h5>
|
||||
<p>Quickly adjust resource allocations to meet changing demands and workload requirements.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-shield-check me-2 text-secondary"></i>Security</h5>
|
||||
<p>Apply security policies, access controls, and encryption to protect your compute resources.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-arrow-repeat me-2 text-secondary"></i>Backups</h5>
|
||||
<p>Configure automated backup schedules to protect your data and workloads.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-clock-history me-2 text-secondary"></i>History</h5>
|
||||
<p>Access detailed logs and history of resource utilization, deployments, and changes.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4 col-md-6">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-graph-up me-2 text-secondary"></i>Analytics</h5>
|
||||
<p>Gain insights from usage patterns and performance analytics to optimize your deployments.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mt-5">
|
||||
<div class="card-body">
|
||||
<h2><i class="bi bi-rocket-takeoff me-2"></i>Ready to Deploy Compute Resources?</h2>
|
||||
<p class="lead">Start exploring available compute resources to find the perfect fit for your needs.</p>
|
||||
<div class="mt-3">
|
||||
<a href="/marketplace/compute" class="btn btn-primary me-2">Explore Compute Marketplace</a>
|
||||
<a href="/docs" class="btn btn-outline-secondary">Back to Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
283
src/views/docs/gateways.html
Normal file
283
src/views/docs/gateways.html
Normal file
@@ -0,0 +1,283 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}Mycelium Gateways - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>Mycelium Gateways</h1>
|
||||
<p class="lead">Comprehensive guide to internet connectivity services in the ThreeFold ecosystem.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Overview</h2>
|
||||
<p>Mycelium Gateways are distributed network access points that provide secure, peer-to-peer internet connectivity services within the ThreeFold ecosystem. These gateways facilitate routing, name resolution, and secure access to resources across the network.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Key Concept</h5>
|
||||
<p class="mb-0">Mycelium Gateways represent a fundamental shift from centralized internet infrastructure to a distributed, resilient network model where connectivity is provided through a mesh of interconnected nodes rather than traditional ISPs.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Core Functions</h2>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-globe me-2 text-primary"></i>Internet Access</h5>
|
||||
<p class="card-text">Provide secure connection points between the ThreeFold Grid and the traditional internet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-signpost-split me-2 text-primary"></i>Traffic Routing</h5>
|
||||
<p class="card-text">Intelligently route network traffic using optimized pathways for improved performance.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-lock me-2 text-primary"></i>Security</h5>
|
||||
<p class="card-text">Implement encryption, access controls, and security protocols to protect network traffic.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-diagram-3 me-2 text-primary"></i>Mesh Networking</h5>
|
||||
<p class="card-text">Create resilient, self-healing network topologies that adapt to changing conditions.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-search me-2 text-primary"></i>Name Resolution</h5>
|
||||
<p class="card-text">Provide decentralized alternatives to DNS for locating resources on the network.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-speedometer2 me-2 text-primary"></i>Bandwidth Management</h5>
|
||||
<p class="card-text">Optimize bandwidth allocation and quality of service for different types of traffic.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Gateway Types</h2>
|
||||
<p>The Mycelium Gateway ecosystem comprises several specialized gateway types, each optimized for specific connectivity needs:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Standard Gateways</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>General-purpose gateways providing basic connectivity services:</strong></p>
|
||||
<ul>
|
||||
<li>Internet access with moderate bandwidth</li>
|
||||
<li>Basic security features</li>
|
||||
<li>Standard routing capabilities</li>
|
||||
<li>Suitable for personal and small business use</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">High-Performance Gateways</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Enhanced gateways designed for intensive bandwidth requirements:</strong></p>
|
||||
<ul>
|
||||
<li>High-throughput connections</li>
|
||||
<li>Low latency optimization</li>
|
||||
<li>Advanced traffic shaping</li>
|
||||
<li>Ideal for streaming, gaming, and business applications</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Secure Gateways</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Security-focused gateways with enhanced protection features:</strong></p>
|
||||
<ul>
|
||||
<li>End-to-end encryption</li>
|
||||
<li>Advanced threat detection</li>
|
||||
<li>Privacy-preserving routing</li>
|
||||
<li>Perfect for sensitive data and communications</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Edge Gateways</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Distributed gateways positioned at network edges for reduced latency:</strong></p>
|
||||
<ul>
|
||||
<li>Geographically optimized connections</li>
|
||||
<li>Content delivery capabilities</li>
|
||||
<li>Local processing of edge data</li>
|
||||
<li>Suited for IoT and real-time applications</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Credits Exchange Mechanism</h2>
|
||||
<p>Mycelium Gateways operate on a bandwidth consumption model within the Credits ecosystem:</p>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th>Aspect</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Payment Model</strong></td>
|
||||
<td>Pay-as-you-go based on actual bandwidth consumption (measured in GB)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Pricing Factors</strong></td>
|
||||
<td>Gateway type, bandwidth quality, geographic location, security features</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Billing Cycle</strong></td>
|
||||
<td>Real-time metering with periodic settlement (typically monthly)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Provider Compensation</strong></td>
|
||||
<td>Gateway operators receive Credits proportional to the bandwidth they provide</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Resource Allocation</strong></td>
|
||||
<td>Dynamic allocation based on network conditions and user requirements</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning mt-4">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-exclamation-triangle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Bandwidth Estimation</h5>
|
||||
<p class="mb-0">When planning your gateway usage, estimate your bandwidth requirements carefully. Unexpected high-bandwidth activities can result in higher Credits consumption. The marketplace provides tools to help monitor and control your usage.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Technical Architecture</h2>
|
||||
<p>Mycelium Gateways implement a sophisticated technical architecture that enables their distributed capabilities:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h5 class="mb-3"><i class="bi bi-layers me-2 text-secondary"></i>Network Stack</h5>
|
||||
<ul class="list-group mb-4">
|
||||
<li class="list-group-item"><strong>Physical Layer:</strong> Diverse connectivity options including fiber, wireless, and satellite</li>
|
||||
<li class="list-group-item"><strong>Data Link Layer:</strong> Enhanced Ethernet with optimized frame processing</li>
|
||||
<li class="list-group-item"><strong>Network Layer:</strong> IPv6-first approach with IPv4 compatibility</li>
|
||||
<li class="list-group-item"><strong>Transport Layer:</strong> Optimized TCP/UDP with custom congestion control</li>
|
||||
<li class="list-group-item"><strong>Application Layer:</strong> Protocol-aware optimizations</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h5 class="mb-3"><i class="bi bi-gear me-2 text-secondary"></i>Key Components</h5>
|
||||
<ul class="list-group mb-4">
|
||||
<li class="list-group-item"><strong>Routing Engine:</strong> Distributed path selection algorithms</li>
|
||||
<li class="list-group-item"><strong>Security Suite:</strong> Multi-layered protection mechanisms</li>
|
||||
<li class="list-group-item"><strong>Bandwidth Manager:</strong> Adaptive traffic shaping</li>
|
||||
<li class="list-group-item"><strong>Mesh Coordinator:</strong> Inter-gateway communication and topology</li>
|
||||
<li class="list-group-item"><strong>Telemetry System:</strong> Performance monitoring and reporting</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Getting Started with Mycelium Gateways</h2>
|
||||
<p>To begin using Mycelium Gateways for your connectivity needs:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-search fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">1. Assess Your Needs</h5>
|
||||
<p class="card-text">Determine your bandwidth requirements, security needs, and geographic preferences.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-cart fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">2. Select a Gateway</h5>
|
||||
<p class="card-text">Browse available gateways in the marketplace and choose one that meets your criteria.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-pc-display fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">3. Configure Access</h5>
|
||||
<p class="card-text">Set up your devices to connect through the gateway using provided configuration details.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mt-5">
|
||||
<div class="card-body">
|
||||
<h2><i class="bi bi-globe2 me-2"></i>Ready to Enhance Your Connectivity?</h2>
|
||||
<p class="lead">Explore available Mycelium Gateways to find the perfect connectivity solution for your needs.</p>
|
||||
<div class="mt-3">
|
||||
<a href="/marketplace/gateways" class="btn btn-primary me-2">Browse Gateways</a>
|
||||
<a href="/docs" class="btn btn-outline-secondary">Back to Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
118
src/views/docs/getting_started.html
Normal file
118
src/views/docs/getting_started.html
Normal file
@@ -0,0 +1,118 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}Getting Started - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>Getting Started with Project Mycelium</h1>
|
||||
<p class="lead">A step-by-step guide to begin your journey with the ThreeFold ecosystem.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Welcome to Project Mycelium</h2>
|
||||
<p>This guide will help you get started with the Project Mycelium platform, covering everything from account creation to making your first transaction.</p>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Step 1: Create an Account</h2>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-person-plus me-2 text-primary"></i>Registration Process</h5>
|
||||
<p>Creating an account on the Project Mycelium is simple and straightforward:</p>
|
||||
<ol>
|
||||
<li>Navigate to the <a href="/register">Registration Page</a></li>
|
||||
<li>Enter your email address and create a secure password</li>
|
||||
<li>Verify your email address through the confirmation link sent to your inbox</li>
|
||||
<li>Complete your profile by adding required information</li>
|
||||
</ol>
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>Note:</strong> If you already have a ThreeFold Connect identity, you can use it to sign in directly.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Step 2: Setup Your Credits Wallet</h2>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-wallet2 me-2 text-primary"></i>Wallet Configuration</h5>
|
||||
<p>To participate in the marketplace, you'll need a USD Credits wallet:</p>
|
||||
<ol>
|
||||
<li>Navigate to the Dashboard and select the "Wallet" section</li>
|
||||
<li>Follow the prompts to create a new Credits wallet</li>
|
||||
<li>Record your recovery phrase and store it in a secure location</li>
|
||||
<li>Add Credits to your wallet through one of the available methods</li>
|
||||
</ol>
|
||||
<p>For more detailed information about Credits and wallet management, visit the <a href="/docs/credits">USD Credits documentation</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Step 3: Explore the Marketplace</h2>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-shop me-2 text-primary"></i>Discovering Resources</h5>
|
||||
<p>Once your account and wallet are set up, you can start exploring the marketplace:</p>
|
||||
<ul>
|
||||
<li><strong>Browse Categories:</strong> Explore different sections such as compute resources, 3Nodes, applications, and services</li>
|
||||
<li><strong>Apply Filters:</strong> Narrow down options based on specifications, location, pricing, and other criteria</li>
|
||||
<li><strong>Compare Options:</strong> Evaluate different offerings to find the best fit for your needs</li>
|
||||
<li><strong>Read Reviews:</strong> Check ratings and feedback from other users</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Step 4: Make Your First Transaction</h2>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-cart-check me-2 text-primary"></i>Transaction Process</h5>
|
||||
<p>When you're ready to make a purchase or exchange resources:</p>
|
||||
<ol>
|
||||
<li>Select the resource or service you wish to acquire</li>
|
||||
<li>Review the details, including specifications and pricing</li>
|
||||
<li>Click "Deploy" or "Purchase" depending on the resource type</li>
|
||||
<li>Confirm the transaction and authorize the Credits transfer</li>
|
||||
<li>Wait for confirmation and follow any additional setup instructions</li>
|
||||
</ol>
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<strong>Important:</strong> Always verify the details of your transaction before confirming. Credits transfers are typically final and may not be reversible.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Step 5: Manage Your Resources</h2>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-gear me-2 text-primary"></i>Resource Management</h5>
|
||||
<p>After acquiring resources or services, you can manage them through your dashboard:</p>
|
||||
<ul>
|
||||
<li>Monitor resource utilization and performance metrics</li>
|
||||
<li>Configure settings and preferences</li>
|
||||
<li>Extend or terminate service agreements</li>
|
||||
<li>Request support or assistance when needed</li>
|
||||
</ul>
|
||||
<p>For specific management instructions, refer to the documentation for each resource type.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mt-5">
|
||||
<div class="card-body">
|
||||
<h2><i class="bi bi-question-circle me-2"></i>Need Further Assistance?</h2>
|
||||
<p class="lead">Our community is here to help you get started.</p>
|
||||
<div class="mt-3">
|
||||
<a href="https://forum.threefold.io" class="btn btn-primary me-2">Join Community Forum</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-primary me-2">Contact Support</a>
|
||||
<a href="/docs" class="btn btn-outline-secondary">Back to Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
196
src/views/docs/index.html
Normal file
196
src/views/docs/index.html
Normal file
@@ -0,0 +1,196 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}Documentation - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>Project Mycelium Documentation</h1>
|
||||
<p class="lead">Welcome to the comprehensive guide to using the Project Mycelium platform.</p>
|
||||
|
||||
<div class="alert alert-info mb-4">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Documentation Overview</h5>
|
||||
<p>This documentation provides detailed information about the Project Mycelium, its components, and how to effectively use the platform.</p>
|
||||
<p>Use the sidebar navigation to explore different sections of the documentation.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Introduction</h2>
|
||||
<p>The Project Mycelium is an all-in-one platform facilitating the exchange of value through the USD credits system. It connects providers and users, enabling the discovery, acquisition, and management of various resources and services within a decentralized ecosystem.</p>
|
||||
<p>Our vision is a world where internet infrastructure and services are distributed, secure, and maintain user sovereignty. The marketplace is our solution to bring this vision to life, providing a platform where anyone can access or provide digital resources in a fair and transparent way.</p>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Core Marketplace Categories</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Marketplace</th>
|
||||
<th>Description</th>
|
||||
<th>Exchange Mechanism</th>
|
||||
<th>Documentation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Compute Resources (Slices)</strong></td>
|
||||
<td>Primary marketplace for compute capacity</td>
|
||||
<td>Credits transferred based on resource utilization</td>
|
||||
<td><a href="/docs/compute" class="btn btn-sm btn-outline-primary">Learn More</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>3Nodes</strong></td>
|
||||
<td>Physical computing hardware marketplace</td>
|
||||
<td>Credits transferred based on hardware value</td>
|
||||
<td><a href="/docs/3nodes" class="btn btn-sm btn-outline-primary">Learn More</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Mycelium Gateways</strong></td>
|
||||
<td>Internet connectivity services</td>
|
||||
<td>Credits paid based on bandwidth consumption</td>
|
||||
<td><a href="/docs/gateways" class="btn btn-sm btn-outline-primary">Learn More</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Application Solutions</strong></td>
|
||||
<td>Pre-configured, self-healing applications</td>
|
||||
<td>Credits paid to solution providers for application management while users maintain sovereignty</td>
|
||||
<td><a href="/docs/applications" class="btn btn-sm btn-outline-primary">Learn More</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Human Energy Services</strong></td>
|
||||
<td>Professional technical services</td>
|
||||
<td>Credits transferred based on agreed rates</td>
|
||||
<td><a href="/docs/services" class="btn btn-sm btn-outline-primary">Learn More</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Core Principles</h2>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-lock me-2"></i>Sovereignty</h5>
|
||||
<p class="card-text">Consumers maintain control over their resources and deployed solutions.</p>
|
||||
<p class="small text-muted">Learn how we ensure user sovereignty through our technical architecture and governance model.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-eye me-2"></i>Transparency</h5>
|
||||
<p class="card-text">Clear pricing and reputation metrics for all marketplace participants.</p>
|
||||
<p class="small text-muted">Discover how our transparent systems build trust across the ecosystem.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-diagram-3 me-2"></i>Decentralization</h5>
|
||||
<p class="card-text">Distributed architecture with no single point of control or failure.</p>
|
||||
<p class="small text-muted">Explore how our decentralized architecture enhances security and resilience.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-people me-2"></i>Community</h5>
|
||||
<p class="card-text">Built by and for the community, with fair and inclusive participation.</p>
|
||||
<p class="small text-muted">Learn about our community governance model and how to get involved.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Getting Started</h2>
|
||||
<p>Ready to dive in? Here's how to get started with the Project Mycelium:</p>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-person-plus-fill fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">1. Create an Account</h5>
|
||||
<p class="card-text">Sign up and verify your identity to join the ThreeFold ecosystem.</p>
|
||||
<a href="/register" class="btn btn-outline-primary mt-2">Register Now</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-wallet2 fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">2. Setup Credits Wallet</h5>
|
||||
<p class="card-text">Configure your credits wallet to participate in marketplace transactions.</p>
|
||||
<a href="/docs/credits" class="btn btn-outline-primary mt-2">Credits Guide</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-shop fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">3. Explore the Marketplace</h5>
|
||||
<p class="card-text">Browse available resources, applications, and services.</p>
|
||||
<a href="/marketplace" class="btn btn-outline-primary mt-2">Visit Marketplace</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Need Help?</h2>
|
||||
<p>If you can't find what you're looking for in the documentation, there are several ways to get help:</p>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-chat-dots me-2"></i>Community Forum</h5>
|
||||
<p>Join our community forum to ask questions and share your experiences.</p>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">Visit Forum</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-github me-2"></i>GitHub Issues</h5>
|
||||
<p>Report bugs or request features through our GitHub repository.</p>
|
||||
<a href="#" class="btn btn-sm btn-outline-secondary">Open Issue</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5><i class="bi bi-envelope me-2"></i>Contact Support</h5>
|
||||
<p>Reach out to our support team for personalized assistance.</p>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-secondary" target="_blank">Contact</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
289
src/views/docs/layout.html
Normal file
289
src/views/docs/layout.html
Normal file
@@ -0,0 +1,289 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar Toggle Button (mobile only) -->
|
||||
<button class="btn sidebar-toggle d-md-none" id="sidebarToggleBtn" aria-label="Toggle sidebar navigation" aria-expanded="false" aria-controls="sidebar">
|
||||
<i class="bi bi-list"></i> Menu
|
||||
</button>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse" id="sidebar">
|
||||
<div class="position-sticky pt-3">
|
||||
<h5 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mb-1 text-muted">
|
||||
<span>Documentation</span>
|
||||
</h5>
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'overview' %}active{% endif %}" href="/docs">
|
||||
<i class="bi bi-book me-1"></i>
|
||||
Overview
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'getting_started' %}active{% endif %}" href="/docs/getting-started">
|
||||
<i class="bi bi-check-circle me-1"></i>
|
||||
Getting Started
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mb-1 text-muted">
|
||||
<span>Marketplace</span>
|
||||
</h6>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'compute' %}active{% endif %}" href="/docs/compute">
|
||||
<i class="bi bi-cpu me-1"></i>
|
||||
Compute Resources
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == '3nodes' %}active{% endif %}" href="/docs/3nodes">
|
||||
<i class="bi bi-hdd-rack me-1"></i>
|
||||
3Nodes
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'gateways' %}active{% endif %}" href="/docs/gateways">
|
||||
<i class="bi bi-globe me-1"></i>
|
||||
Mycelium Gateways
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'applications' %}active{% endif %}" href="/docs/applications">
|
||||
<i class="bi bi-app me-1"></i>
|
||||
Application Solutions
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'services' %}active{% endif %}" href="/docs/services">
|
||||
<i class="bi bi-person-workspace me-1"></i>
|
||||
Human Energy Services
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mb-1 text-muted">
|
||||
<span>Core Concepts</span>
|
||||
</h6>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'credits' %}active{% endif %}" href="/docs/credits">
|
||||
<i class="bi bi-currency-dollar me-1"></i>
|
||||
USD Credits
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'slices' %}active{% endif %}" href="/docs/slices">
|
||||
<i class="bi bi-grid-3x3 me-1"></i>
|
||||
Slices
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'certification' %}active{% endif %}" href="/docs/certification">
|
||||
<i class="bi bi-patch-check me-1"></i>
|
||||
Certification
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item mt-3">
|
||||
<h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mb-1 text-muted">
|
||||
<span>Developer Tools</span>
|
||||
</h6>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'api' %}active{% endif %}" href="/docs/api">
|
||||
<i class="bi bi-code-slash me-1"></i>
|
||||
API Documentation
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content-wrapper position-relative">
|
||||
<!-- Sidebar Backdrop (mobile only) - positioned here so it doesn't cover the sidebar -->
|
||||
<div class="sidebar-backdrop d-md-none" id="sidebarBackdrop"></div>
|
||||
{% block docs_content %}
|
||||
<!-- Content will be injected here by child templates -->
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<!-- Add Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css">
|
||||
|
||||
<style>
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 56px; /* Navbar height */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
padding: 20px 0 0;
|
||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||
height: 100%; /* Full height */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Footer should only appear on the right side */
|
||||
@media (min-width: 768px) {
|
||||
.footer {
|
||||
margin-left: 25% !important; /* Matches the width of col-md-3 */
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.footer {
|
||||
margin-left: 16.666667% !important; /* Matches the width of col-lg-2 */
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-heading {
|
||||
font-size: .75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
color: #2470dc;
|
||||
}
|
||||
|
||||
.docs-content {
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.doc-section {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.doc-section h2 {
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.doc-section h3 {
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.doc-section p {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.doc-section ul, .doc-section ol {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.doc-section pre {
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 4px;
|
||||
padding: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.doc-section code {
|
||||
background-color: #f8f9fa;
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.doc-section table {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
margin-bottom: 1rem;
|
||||
background-color: transparent;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.doc-section table th,
|
||||
.doc-section table td {
|
||||
padding: 0.75rem;
|
||||
vertical-align: top;
|
||||
border-top: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.doc-section table thead th {
|
||||
vertical-align: bottom;
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
}
|
||||
|
||||
/* Adjust for fixed navbar */
|
||||
main.py-4 {
|
||||
padding-top: 4.5rem !important;
|
||||
}
|
||||
|
||||
/* Removed conflicting media query */
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const sidebarToggleBtn = document.getElementById('sidebarToggleBtn');
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
|
||||
|
||||
// Ensure clean state on page load
|
||||
sidebar.classList.remove('show');
|
||||
sidebarBackdrop.classList.remove('show');
|
||||
sidebarToggleBtn.setAttribute('aria-expanded', 'false');
|
||||
|
||||
// Toggle sidebar visibility
|
||||
sidebarToggleBtn.addEventListener('click', function(event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
|
||||
// Toggle visibility
|
||||
sidebar.classList.toggle('show');
|
||||
sidebarBackdrop.classList.toggle('show');
|
||||
|
||||
// Set aria-expanded for accessibility
|
||||
const isExpanded = sidebar.classList.contains('show');
|
||||
sidebarToggleBtn.setAttribute('aria-expanded', isExpanded);
|
||||
});
|
||||
|
||||
// Close sidebar when clicking on backdrop
|
||||
sidebarBackdrop.addEventListener('click', function(event) {
|
||||
event.stopPropagation();
|
||||
sidebar.classList.remove('show');
|
||||
sidebarBackdrop.classList.remove('show');
|
||||
sidebarToggleBtn.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
// Close sidebar when clicking on any link inside it
|
||||
const sidebarLinks = sidebar.querySelectorAll('a.nav-link');
|
||||
sidebarLinks.forEach(link => {
|
||||
link.addEventListener('click', function(event) {
|
||||
// Don't stop event propagation - let the link work
|
||||
setTimeout(function() {
|
||||
sidebar.classList.remove('show');
|
||||
sidebarBackdrop.classList.remove('show');
|
||||
sidebarToggleBtn.setAttribute('aria-expanded', 'false');
|
||||
}, 100); // Small delay to ensure the link click happens
|
||||
});
|
||||
});
|
||||
|
||||
// Ensure links are clickable
|
||||
sidebar.addEventListener('click', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
430
src/views/docs/services.html
Normal file
430
src/views/docs/services.html
Normal file
@@ -0,0 +1,430 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}Human Energy Services - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>Human Energy Services</h1>
|
||||
<p class="lead">Professional technical services available through the Project Mycelium.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Overview</h2>
|
||||
<p>Human Energy Services represent the human expertise component of the ThreeFold ecosystem. These services connect professionals with specialized technical skills to users who need assistance with projects, deployments, and optimizations. Unlike traditional freelance marketplaces, Human Energy Services are fully integrated into the ThreeFold ecosystem, using USD Credits for payments and focusing on technical services relevant to the ThreeFold Grid.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Key Concept</h5>
|
||||
<p class="mb-0">Human Energy Services acknowledge that technological solutions sometimes require human expertise. By integrating these services directly into the marketplace, ThreeFold creates a complete ecosystem where both automated and human-delivered solutions are available with the same seamless experience.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Service Categories</h2>
|
||||
<p>The Human Energy Services marketplace offers expertise across a wide range of technical domains:</p>
|
||||
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-code-square me-2 text-primary"></i>Development</h5>
|
||||
<p class="card-text">Custom software development, coding, and programming services.</p>
|
||||
<ul class="small text-muted">
|
||||
<li>Application development</li>
|
||||
<li>Smart contract programming</li>
|
||||
<li>API integration</li>
|
||||
<li>Frontend/backend development</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-diagram-3 me-2 text-primary"></i>Architecture</h5>
|
||||
<p class="card-text">System design, architecture planning, and infrastructure optimization.</p>
|
||||
<ul class="small text-muted">
|
||||
<li>Solution architecture</li>
|
||||
<li>System optimization</li>
|
||||
<li>Scalability planning</li>
|
||||
<li>Technical roadmapping</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-hdd-rack me-2 text-primary"></i>Deployment</h5>
|
||||
<p class="card-text">Setup, configuration, and deployment of applications and infrastructure.</p>
|
||||
<ul class="small text-muted">
|
||||
<li>3Node configuration</li>
|
||||
<li>Application deployment</li>
|
||||
<li>Network setup</li>
|
||||
<li>Migration services</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-check me-2 text-primary"></i>Security</h5>
|
||||
<p class="card-text">Security assessments, hardening, and implementation of security measures.</p>
|
||||
<ul class="small text-muted">
|
||||
<li>Security audits</li>
|
||||
<li>Penetration testing</li>
|
||||
<li>Security design review</li>
|
||||
<li>Encryption implementation</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-headset me-2 text-primary"></i>Support</h5>
|
||||
<p class="card-text">Ongoing technical support, troubleshooting, and maintenance services.</p>
|
||||
<ul class="small text-muted">
|
||||
<li>Technical troubleshooting</li>
|
||||
<li>Performance optimization</li>
|
||||
<li>System monitoring</li>
|
||||
<li>Update management</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-mortarboard me-2 text-primary"></i>Training</h5>
|
||||
<p class="card-text">Educational services, knowledge transfer, and skill development.</p>
|
||||
<ul class="small text-muted">
|
||||
<li>Technical workshops</li>
|
||||
<li>One-on-one mentoring</li>
|
||||
<li>Team training</li>
|
||||
<li>Documentation creation</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Provider Certification</h2>
|
||||
<p>Service providers in the ThreeFold ecosystem undergo a certification process to ensure quality and reliability:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-star-fill me-2"></i>Basic</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Entry-level verification:</strong></p>
|
||||
<ul>
|
||||
<li>Identity verification</li>
|
||||
<li>Basic skills assessment</li>
|
||||
<li>Terms agreement</li>
|
||||
<li>Community participation</li>
|
||||
</ul>
|
||||
<p class="text-muted small mt-3">Providers at this level can offer services but have limited visibility in search results.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-stars me-2"></i>Verified</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Intermediate verification:</strong></p>
|
||||
<ul>
|
||||
<li>Comprehensive skills validation</li>
|
||||
<li>Client testimonials</li>
|
||||
<li>Quality standards commitment</li>
|
||||
<li>Active ecosystem participation</li>
|
||||
</ul>
|
||||
<p class="text-muted small mt-3">Verified providers receive standard visibility and can participate in more complex projects.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-award me-2"></i>Certified</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Highest level of verification:</strong></p>
|
||||
<ul>
|
||||
<li>Expert-level skills validation</li>
|
||||
<li>Proven track record</li>
|
||||
<li>Quality assurance guarantees</li>
|
||||
<li>ThreeFold certification exam</li>
|
||||
</ul>
|
||||
<p class="text-muted small mt-3">Certified providers receive featured placement, higher rates, and access to enterprise projects.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Engagement Models</h2>
|
||||
<p>Human Energy Services can be engaged through several different models based on project requirements and timeframes:</p>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th>Model</th>
|
||||
<th>Description</th>
|
||||
<th>Best For</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Fixed Project</strong></td>
|
||||
<td>Pre-defined scope with fixed deliverables and timeline</td>
|
||||
<td>Well-defined projects with clear requirements</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Hourly Rate</strong></td>
|
||||
<td>Pay for services based on actual time spent</td>
|
||||
<td>Evolving projects, ongoing support, variable scope</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Retainer</strong></td>
|
||||
<td>Reserve dedicated time each month at a guaranteed rate</td>
|
||||
<td>Ongoing relationships, consistent support needs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Support Package</strong></td>
|
||||
<td>Pre-purchased support hours with service level agreements</td>
|
||||
<td>Production systems requiring quick response times</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Collaborative</strong></td>
|
||||
<td>Work alongside your team in a collaborative capacity</td>
|
||||
<td>Knowledge transfer, team augmentation</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Credits Exchange Mechanism</h2>
|
||||
<p>Human Energy Services operate on a straightforward Credits-based payment model:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<h5 class="mb-3"><i class="bi bi-cash-coin me-2 text-success"></i>Payment Structure</h5>
|
||||
<ul class="list-group mb-4">
|
||||
<li class="list-group-item d-flex align-items-center">
|
||||
<i class="bi bi-check-circle-fill me-2 text-success"></i>
|
||||
<div>
|
||||
<strong>Transparent Pricing</strong>
|
||||
<p class="mb-0 small text-muted">All service rates are clearly displayed in USD Credits before engagement</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex align-items-center">
|
||||
<i class="bi bi-check-circle-fill me-2 text-success"></i>
|
||||
<div>
|
||||
<strong>Milestone-Based Payments</strong>
|
||||
<p class="mb-0 small text-muted">Credits released upon completion of pre-defined milestones</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex align-items-center">
|
||||
<i class="bi bi-check-circle-fill me-2 text-success"></i>
|
||||
<div>
|
||||
<strong>Escrow Protection</strong>
|
||||
<p class="mb-0 small text-muted">Funds held in escrow until work is completed and approved</p>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item d-flex align-items-center">
|
||||
<i class="bi bi-check-circle-fill me-2 text-success"></i>
|
||||
<div>
|
||||
<strong>Provider-Set Rates</strong>
|
||||
<p class="mb-0 small text-muted">Service providers set their own rates based on expertise level</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h5 class="mb-3"><i class="bi bi-gear-wide-connected me-2 text-success"></i>Process Flow</h5>
|
||||
<ol class="list-group list-group-numbered mb-4">
|
||||
<li class="list-group-item">
|
||||
<strong>Service Selection</strong>
|
||||
<p class="mb-0 small text-muted">Client selects a service and provider from the marketplace</p>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>Scope Agreement</strong>
|
||||
<p class="mb-0 small text-muted">Client and provider agree on deliverables, timeline, and payment terms</p>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>Credits Allocation</strong>
|
||||
<p class="mb-0 small text-muted">Client allocates agreed Credits amount to the project escrow</p>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>Work & Milestones</strong>
|
||||
<p class="mb-0 small text-muted">Provider performs work and delivers milestone achievements</p>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>Verification & Payment</strong>
|
||||
<p class="mb-0 small text-muted">Client approves deliverables and Credits are released from escrow to provider</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-warning mt-3">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-exclamation-triangle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Dispute Resolution</h5>
|
||||
<p class="mb-0">In case of disagreements about deliverable quality or scope, the Project Mycelium offers a structured dispute resolution process. This involves neutral third-party evaluation based on the agreed statement of work. Make sure to clearly document expectations before beginning any service engagement.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Finding the Right Provider</h2>
|
||||
<p>The Marketplace provides several tools to help you find the perfect service provider for your needs:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-search me-2 text-primary"></i>Search Filters</h5>
|
||||
<p>Refine provider search using multiple criteria:</p>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<ul>
|
||||
<li>Service category</li>
|
||||
<li>Expertise level</li>
|
||||
<li>Certification tier</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<ul>
|
||||
<li>Rating threshold</li>
|
||||
<li>Price range</li>
|
||||
<li>Availability</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-star me-2 text-primary"></i>Provider Profiles</h5>
|
||||
<p>Comprehensive provider information:</p>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<ul>
|
||||
<li>Portfolio/previous work</li>
|
||||
<li>Client reviews</li>
|
||||
<li>Response time</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<ul>
|
||||
<li>Completion rate</li>
|
||||
<li>Skills validation</li>
|
||||
<li>TF ecosystem contribution</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex align-items-center bg-light p-3 rounded mb-4">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-lightbulb-fill fs-3 text-warning"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Pro Tip</h5>
|
||||
<p class="mb-0">Many providers offer a free initial consultation to discuss your needs and determine if they're the right fit for your project. Use this opportunity to clearly communicate your requirements and assess their understanding before committing to a paid engagement.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Becoming a Service Provider</h2>
|
||||
<p>If you have valuable technical skills, you can join the ThreeFold ecosystem as a service provider:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-person-plus-fill fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">1. Create Provider Profile</h5>
|
||||
<p class="card-text">Complete your service provider profile with skills, experience, and portfolio.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-award-fill fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">2. Verification Process</h5>
|
||||
<p class="card-text">Complete required verification steps based on your desired certification level.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body text-center">
|
||||
<div class="mb-3">
|
||||
<i class="bi bi-send-check-fill fs-1 text-primary"></i>
|
||||
</div>
|
||||
<h5 class="card-title">3. Start Offering Services</h5>
|
||||
<p class="card-text">Create service listings highlighting your expertise and start accepting clients.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Provider Resources</h5>
|
||||
<p class="mb-0">ThreeFold provides extensive resources to help service providers succeed, including training materials, best practices guides, contract templates, and client management tools. Explore the <a href="#" class="alert-link">Provider Resources</a> area to learn more.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mt-5">
|
||||
<div class="card-body">
|
||||
<h2><i class="bi bi-people me-2"></i>Ready to Connect with Technical Experts?</h2>
|
||||
<p class="lead">Browse available service providers to find skilled professionals for your technical needs.</p>
|
||||
<div class="mt-3">
|
||||
<a href="/marketplace/services" class="btn btn-primary me-2">Find Service Providers</a>
|
||||
<a href="/docs" class="btn btn-outline-secondary">Back to Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
524
src/views/docs/slices.html
Normal file
524
src/views/docs/slices.html
Normal file
@@ -0,0 +1,524 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}Slices - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="my-4">
|
||||
<h1>Slices</h1>
|
||||
<p class="lead">Understanding the fundamental unit of compute capacity in the ThreeFold ecosystem.</p>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Overview</h2>
|
||||
<p>Slices represent the core unit of compute capacity within the ThreeFold Grid. They are standardized divisions of physical computing hardware (3Nodes) that can be allocated and managed as independent virtual resources. Slices form the foundation of all deployments on the ThreeFold Grid and serve as the primary unit of exchange for computational resources.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Key Concept</h5>
|
||||
<p class="mb-0">Slices abstract away the underlying physical infrastructure, providing a consistent and standardized way to measure, allocate, and exchange computing capacity across the entire ThreeFold Grid.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Slice Composition</h2>
|
||||
<p>Each slice is a bundle of computing resources that includes:</p>
|
||||
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-4">
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-cpu me-2 text-primary"></i>Compute (vCPU)</h5>
|
||||
<p class="card-text">Processing power expressed as virtual CPU cores with specific performance characteristics.</p>
|
||||
<p class="small text-muted fst-italic">Measured in compute units (CU)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-memory me-2 text-primary"></i>Memory</h5>
|
||||
<p class="card-text">RAM allocation for running applications and workloads with defined capacity.</p>
|
||||
<p class="small text-muted fst-italic">Measured in memory units (MU)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-device-ssd me-2 text-primary"></i>Storage</h5>
|
||||
<p class="card-text">Persistent data storage with specified capacity and performance characteristics.</p>
|
||||
<p class="small text-muted fst-italic">Measured in storage units (SU)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-hdd-network me-2 text-primary"></i>Network</h5>
|
||||
<p class="card-text">Bandwidth allocation for data transfer between the slice and other network points.</p>
|
||||
<p class="small text-muted fst-italic">Measured in network units (NU)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-lock me-2 text-primary"></i>Security Layer</h5>
|
||||
<p class="card-text">Zero-OS secure runtime environment that ensures isolation and security.</p>
|
||||
<p class="small text-muted fst-italic">Built into every slice</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-gear me-2 text-primary"></i>Management Layer</h5>
|
||||
<p class="card-text">Tools and interfaces for monitoring and controlling the slice resources.</p>
|
||||
<p class="small text-muted fst-italic">Accessible via API and dashboard</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Slice Resource Units</h2>
|
||||
<p>ThreeFold uses standardized units to measure and quantify the resources in each slice:</p>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th>Resource Unit</th>
|
||||
<th>Definition</th>
|
||||
<th>Equivalent To</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Compute Unit (CU)</strong></td>
|
||||
<td>Standardized measure of processing power</td>
|
||||
<td>2 virtual CPU cores with guaranteed performance</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Memory Unit (MU)</strong></td>
|
||||
<td>Standardized measure of RAM capacity</td>
|
||||
<td>4 GB of RAM with dedicated allocation</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Storage Unit (SU)</strong></td>
|
||||
<td>Standardized measure of storage capacity</td>
|
||||
<td>1 TB of SSD-equivalent storage space</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Network Unit (NU)</strong></td>
|
||||
<td>Standardized measure of network transfer</td>
|
||||
<td>1 GB of data transfer capacity</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-secondary mt-4">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-calculator-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Resource Calculation</h5>
|
||||
<p class="mb-0">The system automatically calculates the appropriate number of resource units required for your specific workload based on your deployment specifications. You can use the <a href="#resource-calculator" class="alert-link">Resource Calculator</a> to estimate the required units for your use case.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Slice Types</h2>
|
||||
<p>The ThreeFold Grid offers different types of slices optimized for specific workloads:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-menu-button-wide me-2"></i>General Purpose Slices</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Balanced resources for standard workloads:</strong></p>
|
||||
<ul>
|
||||
<li>Equal distribution of compute, memory, and storage</li>
|
||||
<li>Suitable for most applications and services</li>
|
||||
<li>Flexible configuration options</li>
|
||||
<li>Ideal for web servers, applications, and development environments</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-cpu me-2"></i>Compute-Optimized Slices</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Enhanced processing power for compute-intensive tasks:</strong></p>
|
||||
<ul>
|
||||
<li>Higher ratio of compute units to other resources</li>
|
||||
<li>Optimized for processor-heavy workloads</li>
|
||||
<li>Advanced CPU instruction set availability</li>
|
||||
<li>Ideal for data processing, rendering, and scientific calculations</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-memory me-2"></i>Memory-Optimized Slices</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Enhanced memory allocation for data-intensive applications:</strong></p>
|
||||
<ul>
|
||||
<li>Higher ratio of memory units to other resources</li>
|
||||
<li>Optimized for applications requiring large RAM allocations</li>
|
||||
<li>High-speed memory access patterns</li>
|
||||
<li>Ideal for databases, caching layers, and in-memory analytics</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-device-hdd me-2"></i>Storage-Optimized Slices</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Enhanced storage capacity for data-heavy workloads:</strong></p>
|
||||
<ul>
|
||||
<li>Higher ratio of storage units to other resources</li>
|
||||
<li>Options for SSD or HDD-equivalent performance</li>
|
||||
<li>Optimized I/O performance characteristics</li>
|
||||
<li>Ideal for file servers, object storage, and backup systems</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-gpu-card me-2"></i>GPU Slices</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Access to GPU resources for specialized workloads:</strong></p>
|
||||
<ul>
|
||||
<li>Includes access to GPU computing resources</li>
|
||||
<li>Specialized for graphics and parallel computing</li>
|
||||
<li>Driver and toolkit support</li>
|
||||
<li>Ideal for AI/ML, rendering, and scientific computing</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-lightning me-2"></i>High-Performance Slices</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p><strong>Premium resources with maximum performance guarantees:</strong></p>
|
||||
<ul>
|
||||
<li>Top-tier hardware allocations</li>
|
||||
<li>Guaranteed performance metrics</li>
|
||||
<li>Enhanced bandwidth and low latency</li>
|
||||
<li>Ideal for mission-critical applications and services</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2 id="resource-calculator">Resource Calculator</h2>
|
||||
<p>Use this calculator to estimate the resources needed for your workload:</p>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label for="workloadType" class="form-label">Workload Type</label>
|
||||
<select class="form-select" id="workloadType">
|
||||
<option value="website">Website / Web App</option>
|
||||
<option value="database">Database</option>
|
||||
<option value="container">Container Orchestration</option>
|
||||
<option value="storage">Storage Solution</option>
|
||||
<option value="compute">Compute Workload</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="workloadSize" class="form-label">Expected Scale</label>
|
||||
<select class="form-select" id="workloadSize">
|
||||
<option value="small">Small (Development/Testing)</option>
|
||||
<option value="medium">Medium (Production/Small Team)</option>
|
||||
<option value="large">Large (Business/Enterprise)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="cpuSlider" class="form-label">CPU Cores: <span id="cpuValue">2</span></label>
|
||||
<input type="range" class="form-range" min="1" max="32" value="2" id="cpuSlider">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="ramSlider" class="form-label">Memory (GB): <span id="ramValue">4</span></label>
|
||||
<input type="range" class="form-range" min="1" max="128" value="4" id="ramSlider">
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="storageSlider" class="form-label">Storage (GB): <span id="storageValue">50</span></label>
|
||||
<input type="range" class="form-range" min="10" max="2000" value="50" id="storageSlider">
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<button type="button" class="btn btn-primary" id="calculateBtn">Calculate Resources</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h5 class="mb-0">Estimated Resources</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<h6>Required Resource Units:</h6>
|
||||
<ul>
|
||||
<li><strong>Compute Units (CU):</strong> <span id="cuResult">1</span></li>
|
||||
<li><strong>Memory Units (MU):</strong> <span id="muResult">1</span></li>
|
||||
<li><strong>Storage Units (SU):</strong> <span id="suResult">0.05</span></li>
|
||||
<li><strong>Network Units (NU):</strong> <span id="nuResult">Varies based on usage</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<h6>Recommended Slice Type:</h6>
|
||||
<p id="sliceRecommendation">General Purpose Slice (Small)</p>
|
||||
<p class="small text-muted">This recommendation is an estimate. Actual requirements may vary based on specific workload characteristics and usage patterns.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Managing Slices</h2>
|
||||
<p>The Project Mycelium provides several tools for managing your slices:</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-plus-square me-2 text-success"></i>Slice Provisioning</h5>
|
||||
<p>Creating and allocating new slices:</p>
|
||||
<ul>
|
||||
<li><strong>Marketplace Interface:</strong> Simple UI-based slice creation</li>
|
||||
<li><strong>API Access:</strong> Programmatic slice provisioning</li>
|
||||
<li><strong>Templates:</strong> Pre-configured slice specifications</li>
|
||||
<li><strong>Custom Configuration:</strong> Tailored resource allocations</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-graph-up me-2 text-primary"></i>Monitoring & Scaling</h5>
|
||||
<p>Managing active slices:</p>
|
||||
<ul>
|
||||
<li><strong>Performance Metrics:</strong> Real-time utilization data</li>
|
||||
<li><strong>Scaling Options:</strong> Vertical and horizontal scaling</li>
|
||||
<li><strong>Alerts:</strong> Customizable threshold notifications</li>
|
||||
<li><strong>Usage Reports:</strong> Resource consumption analytics</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-shield-check me-2 text-success"></i>Security & Access</h5>
|
||||
<p>Securing your slices:</p>
|
||||
<ul>
|
||||
<li><strong>Access Controls:</strong> Granular permission settings</li>
|
||||
<li><strong>Network Policies:</strong> Traffic management rules</li>
|
||||
<li><strong>Encryption Options:</strong> Data-at-rest and in-transit protection</li>
|
||||
<li><strong>Security Scanning:</strong> Vulnerability assessment</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3"><i class="bi bi-clock-history me-2 text-primary"></i>Lifecycle Management</h5>
|
||||
<p>Long-term slice administration:</p>
|
||||
<ul>
|
||||
<li><strong>Backup Solutions:</strong> Data protection options</li>
|
||||
<li><strong>Migration Tools:</strong> Moving workloads between slices</li>
|
||||
<li><strong>Version Control:</strong> Configuration history and rollback</li>
|
||||
<li><strong>Retirement Process:</strong> Secure decommissioning</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-section">
|
||||
<h2>Credits Exchange Mechanism</h2>
|
||||
<p>Slices are provisioned and managed through the USD Credits value exchange system:</p>
|
||||
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Slice Economics</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li><strong>Resource-Based Pricing:</strong> Cost calculated based on resource units allocated (in USD)</li>
|
||||
<li><strong>Time-Based Billing:</strong> Pay only for the duration slices are provisioned</li>
|
||||
<li><strong>Optional Reservations:</strong> Discounted rates for long-term commitments</li>
|
||||
<li><strong>Dynamic Allocation:</strong> Scale resources up or down as needed and pay accordingly</li>
|
||||
<li><strong>Provider Selection:</strong> Different rates based on selected resource providers</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="mb-3">Sample Cost Estimation</h5>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Resource</th>
|
||||
<th>Quantity</th>
|
||||
<th>Unit Cost ($/month)</th>
|
||||
<th>Total ($/month)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Compute Units</td>
|
||||
<td>2</td>
|
||||
<td>15</td>
|
||||
<td>30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memory Units</td>
|
||||
<td>1</td>
|
||||
<td>10</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Storage Units</td>
|
||||
<td>0.1</td>
|
||||
<td>5</td>
|
||||
<td>0.5</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Network Units</td>
|
||||
<td>100</td>
|
||||
<td>0.1</td>
|
||||
<td>10</td>
|
||||
</tr>
|
||||
<tr class="table-primary">
|
||||
<td colspan="3"><strong>Total Monthly Cost</strong></td>
|
||||
<td><strong>$50.50</strong></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p class="small text-muted mt-2">This is a sample estimation. Actual costs will vary based on specific resource requirements and provider rates.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-light mt-5">
|
||||
<div class="card-body">
|
||||
<h2><i class="bi bi-grid-3x3-gap me-2"></i>Ready to Provision Slices?</h2>
|
||||
<p class="lead">Start exploring the available compute resources to find the perfect slice configuration for your needs.</p>
|
||||
<div class="mt-3">
|
||||
<a href="/marketplace/compute" class="btn btn-primary me-2">Browse Compute Resources</a>
|
||||
<a href="/docs" class="btn btn-outline-secondary">Back to Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
// Simple JavaScript for the resource calculator
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const cpuSlider = document.getElementById('cpuSlider');
|
||||
const ramSlider = document.getElementById('ramSlider');
|
||||
const storageSlider = document.getElementById('storageSlider');
|
||||
const cpuValue = document.getElementById('cpuValue');
|
||||
const ramValue = document.getElementById('ramValue');
|
||||
const storageValue = document.getElementById('storageValue');
|
||||
const calculateBtn = document.getElementById('calculateBtn');
|
||||
|
||||
cpuSlider.addEventListener('input', function() {
|
||||
cpuValue.textContent = this.value;
|
||||
});
|
||||
|
||||
ramSlider.addEventListener('input', function() {
|
||||
ramValue.textContent = this.value;
|
||||
});
|
||||
|
||||
storageSlider.addEventListener('input', function() {
|
||||
storageValue.textContent = this.value;
|
||||
});
|
||||
|
||||
calculateBtn.addEventListener('click', function() {
|
||||
// Simple calculation for demonstration purposes
|
||||
const cpu = parseInt(cpuSlider.value);
|
||||
const ram = parseInt(ramSlider.value);
|
||||
const storage = parseInt(storageSlider.value);
|
||||
|
||||
document.getElementById('cuResult').textContent = Math.ceil(cpu / 2);
|
||||
document.getElementById('muResult').textContent = Math.ceil(ram / 4);
|
||||
document.getElementById('suResult').textContent = (storage / 1000).toFixed(2);
|
||||
|
||||
// Simple recommendation logic
|
||||
let recommendation = "General Purpose Slice";
|
||||
if (cpu > ram * 2) {
|
||||
recommendation = "Compute-Optimized Slice";
|
||||
} else if (ram > cpu * 2) {
|
||||
recommendation = "Memory-Optimized Slice";
|
||||
} else if (storage > ram * 50) {
|
||||
recommendation = "Storage-Optimized Slice";
|
||||
}
|
||||
|
||||
let size = "(Small)";
|
||||
if (cpu > 8 || ram > 16 || storage > 500) {
|
||||
size = "(Large)";
|
||||
} else if (cpu > 4 || ram > 8 || storage > 100) {
|
||||
size = "(Medium)";
|
||||
}
|
||||
|
||||
document.getElementById('sliceRecommendation').textContent = recommendation + " " + size;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
||||
52
src/views/docs/tfp.html
Normal file
52
src/views/docs/tfp.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{% extends "docs/layout.html" %}
|
||||
|
||||
{% block title %}USD Credits - Project Mycelium{% endblock %}
|
||||
|
||||
{% block docs_content %}
|
||||
<div class="docs-content">
|
||||
<h1>USD Credits</h1>
|
||||
<p class="lead">Project Mycelium uses a simple USD credits system for all transactions.</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<h5>Simple and Intuitive</h5>
|
||||
<p>1 Credit = $1 USD. No complex conversions or confusing terminology.</p>
|
||||
</div>
|
||||
|
||||
<h2>How Credits Work</h2>
|
||||
<ul>
|
||||
<li><strong>Direct USD Pricing:</strong> All products are priced in clear USD amounts</li>
|
||||
<li><strong>Easy Top-up:</strong> Add credits to your wallet with standard payment methods</li>
|
||||
<li><strong>Auto Top-up:</strong> Automatically purchase credits when your balance gets low</li>
|
||||
<li><strong>One-Click Purchasing:</strong> Buy products instantly with the "Buy Now" button</li>
|
||||
</ul>
|
||||
|
||||
<h2>Auto Top-up</h2>
|
||||
<p>Configure automatic credit purchasing for seamless marketplace experience:</p>
|
||||
<ol>
|
||||
<li>Go to your <a href="/dashboard/wallet">Wallet</a></li>
|
||||
<li>Enable Auto Top-up in the settings section</li>
|
||||
<li>Set your threshold (e.g., when credits fall below $10)</li>
|
||||
<li>Set your top-up amount (e.g., purchase $25 when triggered)</li>
|
||||
<li>Choose your payment method</li>
|
||||
</ol>
|
||||
|
||||
<h2>Versatile Purchase Options</h2>
|
||||
<p>The marketplace offers two convenient ways to purchase products:</p>
|
||||
<ul>
|
||||
<li><strong>Buy Now:</strong> Instant one-click purchase with automatic balance management and auto top-up integration</li>
|
||||
<li><strong>Add to Cart:</strong> Traditional shopping cart experience for purchasing multiple items together</li>
|
||||
</ul>
|
||||
|
||||
<div class="alert alert-tip">
|
||||
<strong>Best of Both Worlds:</strong> Use "Buy Now" for quick single purchases, or "Add to Cart" when you want to compare multiple products or make bulk purchases.
|
||||
</div>
|
||||
|
||||
<h2>Getting Started</h2>
|
||||
<ol>
|
||||
<li>Create your Project Mycelium account</li>
|
||||
<li>Add credits to your wallet</li>
|
||||
<li>Browse the marketplace</li>
|
||||
<li>Click "Buy Now" for instant purchases</li>
|
||||
</ol>
|
||||
</div>
|
||||
{% endblock %}
|
||||
110
src/views/home/about.html
Normal file
110
src/views/home/about.html
Normal file
@@ -0,0 +1,110 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}About - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<h1>About Project Mycelium</h1>
|
||||
<p class="lead">A platform connecting the ThreeFold ecosystem and facilitating value exchange.</p>
|
||||
<hr>
|
||||
|
||||
<section class="mb-5">
|
||||
<h2>Our Vision</h2>
|
||||
<p>The Project Mycelium is an all-in-one platform facilitating the exchange of value through the Credits system. It connects providers and users, enabling the discovery, acquisition, and management of various resources and services within a decentralized ecosystem.</p>
|
||||
<p>We believe in a world where internet infrastructure and services are distributed, secure, and maintain user sovereignty. The marketplace is our solution to bring this vision to life, providing a platform where anyone can access or provide digital resources in a fair and transparent way.</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-5">
|
||||
<h2>Core Marketplace Categories</h2>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Marketplace</th>
|
||||
<th>Description</th>
|
||||
<th>Exchange Mechanism</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Compute Resources (Slices)</strong></td>
|
||||
<td>Primary marketplace for compute capacity</td>
|
||||
<td>Credits charged based on resource utilization</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>3Nodes</strong></td>
|
||||
<td>Physical computing hardware marketplace</td>
|
||||
<td>Credits transferred based on hardware value</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Mycelium Gateways</strong></td>
|
||||
<td>Internet connectivity services</td>
|
||||
<td>Credits paid based on bandwidth consumption</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Application Solutions</strong></td>
|
||||
<td>Pre-configured, self-healing applications</td>
|
||||
<td>Users provide slices to solution providers while maintaining sovereignty</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Human Energy Services</strong></td>
|
||||
<td>Professional technical services</td>
|
||||
<td>Credits transferred based on agreed rates</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mb-5">
|
||||
<h2>Core Principles</h2>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-shield-lock me-2"></i>Sovereignty</h5>
|
||||
<p class="card-text">Consumers maintain control over their resources and deployed solutions.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-eye me-2"></i>Transparency</h5>
|
||||
<p class="card-text">Clear pricing and reputation metrics for all marketplace participants.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-diagram-3 me-2"></i>Decentralization</h5>
|
||||
<p class="card-text">Distributed architecture with no single point of control or failure.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-people me-2"></i>Community</h5>
|
||||
<p class="card-text">Built by and for the community, with fair and inclusive participation.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mb-5">
|
||||
<h2>Join the Ecosystem</h2>
|
||||
<p>The Project Mycelium is more than just a platform—it's an ecosystem of innovators, builders, and users working together to create a better digital future. Whether you're looking to access resources for your next project or provide your expertise to others, we invite you to join us.</p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="/register" class="btn btn-primary">Get Started</a>
|
||||
<a href="/marketplace" class="btn btn-outline-secondary">Explore Marketplace</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
157
src/views/home/contact.html
Normal file
157
src/views/home/contact.html
Normal file
@@ -0,0 +1,157 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Contact - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<h1>Contact ThreeFold</h1>
|
||||
<p class="lead">Get in touch with the ThreeFold team and community.</p>
|
||||
<hr>
|
||||
|
||||
<section class="mb-5">
|
||||
<h2>Join the ThreeFold Ecosystem</h2>
|
||||
<p>ThreeFold is an open ecosystem that welcomes contributors, users, and partners from all backgrounds. Whether you're interested in using the platform, contributing to its development, or exploring partnership opportunities, we'd love to hear from you.</p>
|
||||
</section>
|
||||
|
||||
<section class="mb-5">
|
||||
<h2>Contact Information</h2>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<i class="bi bi-envelope-fill fs-3 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Email</h5>
|
||||
<p>For general inquiries: <a href="mailto:info@threefold.io">info@threefold.io</a></p>
|
||||
<p class="mb-0">Please allow 24-48 hours for a response.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<i class="bi bi-chat-square-text-fill fs-3 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Community Forum</h5>
|
||||
<p>Join discussions, ask questions, and connect with the ThreeFold community:</p>
|
||||
<p class="mb-0"><a href="https://forum.threefold.io" target="_blank" rel="noopener noreferrer">forum.threefold.io</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<i class="bi bi-telegram fs-3 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5>Telegram</h5>
|
||||
<p>Join our Telegram group for real-time community discussions:</p>
|
||||
<p class="mb-0"><a href="https://t.me/threefold" target="_blank" rel="noopener noreferrer">https://t.me/threefold</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mb-5">
|
||||
<h2>Get Involved</h2>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-code-square me-2"></i>Developers</h5>
|
||||
<p class="card-text">Contribute to the ThreeFold technology stack and help build the peer-to-peer internet infrastructure.</p>
|
||||
<a href="https://github.com/threefoldtech" target="_blank" rel="noopener noreferrer" class="btn btn-outline-primary">GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-hdd-rack me-2"></i>Farmers</h5>
|
||||
<p class="card-text">Contribute compute capacity to the ThreeFold Grid and earn through the platform's ecosystem.</p>
|
||||
<a href="/docs" class="btn btn-outline-primary">Learn More</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-building me-2"></i>Organizations</h5>
|
||||
<p class="card-text">Explore partnership opportunities for businesses, nonprofits, and other organizations.</p>
|
||||
<a href="mailto:partnerships@threefold.io" class="btn btn-outline-primary">Contact Partnerships</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bi bi-people me-2"></i>Community</h5>
|
||||
<p class="card-text">Join our growing community of enthusiasts, advocates, and users.</p>
|
||||
<a href="https://forum.threefold.io" target="_blank" rel="noopener noreferrer" class="btn btn-outline-primary">Join Forum</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="mb-5">
|
||||
<h2>Frequently Asked Questions</h2>
|
||||
<div class="accordion" id="contactFAQ">
|
||||
<div class="accordion-item">
|
||||
<h3 class="accordion-header" id="headingOne">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
How do I report a bug or technical issue?
|
||||
</button>
|
||||
</h3>
|
||||
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#contactFAQ">
|
||||
<div class="accordion-body">
|
||||
Technical issues can be reported on our <a href="https://github.com/threefoldtech" target="_blank" rel="noopener noreferrer">GitHub repositories</a>. Please check the specific repository related to the component you're experiencing issues with and create a detailed issue report.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h3 class="accordion-header" id="headingTwo">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
||||
How can I schedule a call with the ThreeFold team?
|
||||
</button>
|
||||
</h3>
|
||||
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#contactFAQ">
|
||||
<div class="accordion-body">
|
||||
For specific inquiries that require a direct conversation, please email <a href="mailto:info@threefold.io">info@threefold.io</a> with details about your request and potential meeting times. Our team will follow up to arrange a call.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h3 class="accordion-header" id="headingThree">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
||||
Where can I find the latest news about ThreeFold?
|
||||
</button>
|
||||
</h3>
|
||||
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#contactFAQ">
|
||||
<div class="accordion-body">
|
||||
Stay updated on ThreeFold developments through our <a href="https://forum.threefold.io" target="_blank" rel="noopener noreferrer">community forum</a>, <a href="https://t.me/threefold" target="_blank" rel="noopener noreferrer">Telegram channel</a>, and by following us on social media platforms.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="text-center">
|
||||
<p class="lead">We look forward to connecting with you and building the decentralized internet together.</p>
|
||||
<a href="/" class="btn btn-primary">Back to Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
219
src/views/home/index.html
Normal file
219
src/views/home/index.html
Normal file
@@ -0,0 +1,219 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Home - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Hero Section -->
|
||||
<section class="hero-section">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-7">
|
||||
<h1>Project Mycelium</h1>
|
||||
<p class="lead mb-4">The all-in-one platform for decentralized compute resources, applications, and services within the ThreeFold ecosystem.</p>
|
||||
<div class="d-flex flex-wrap justify-content-center gap-3">
|
||||
<a href="/register" class="btn btn-primary cta-primary">Get Started</a>
|
||||
<a href="/login" class="btn btn-outline-secondary cta-secondary">Log In</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-5">
|
||||
<div class="text-center">
|
||||
<img src="/static/images/logo_light.png" alt="ThreeFold Logo" class="img-fluid" style="max-height: 150px;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Marketplace Preview Section -->
|
||||
<section class="marketplace-preview">
|
||||
<div class="container">
|
||||
<div class="text-center mb-5">
|
||||
<h2>Discover the Project Mycelium</h2>
|
||||
<p class="lead">Find and access resources, applications and services in a sovereign, secure way</p>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-cpu text-primary display-4 mb-3"></i>
|
||||
<h3>Compute Resources</h3>
|
||||
<p>Access compute capacity (slices) from the decentralized ThreeFold Grid.</p>
|
||||
<a href="/marketplace/compute" class="btn btn-sm btn-outline-primary">Explore</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-hdd-rack text-primary display-4 mb-3"></i>
|
||||
<h3>3Nodes</h3>
|
||||
<p>Buy and sell physical computing hardware to support the Grid.</p>
|
||||
<a href="/marketplace/3nodes" class="btn btn-sm btn-outline-primary">Explore</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-app text-primary display-4 mb-3"></i>
|
||||
<h3>Applications</h3>
|
||||
<p>Discover self-healing applications that maintain sovereignty.</p>
|
||||
<a href="/marketplace/applications" class="btn btn-sm btn-outline-primary">Explore</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ Section -->
|
||||
<section class="faq-section">
|
||||
<div class="container">
|
||||
<div class="text-center mb-5">
|
||||
<h2>Frequently Asked Questions</h2>
|
||||
<p class="lead">Common questions about the Project Mycelium</p>
|
||||
</div>
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<div class="accordion" id="faqAccordion">
|
||||
<!-- FAQ Item 1 -->
|
||||
<div class="accordion-item mb-3">
|
||||
<h2 class="accordion-header" id="faqHeading1">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse1" aria-expanded="false" aria-controls="faqCollapse1">
|
||||
What is the Project Mycelium?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="faqCollapse1" class="accordion-collapse collapse" aria-labelledby="faqHeading1" data-bs-parent="#faqAccordion">
|
||||
<div class="accordion-body">
|
||||
The Project Mycelium is a central platform facilitating the exchange of value through the Credits system. It connects providers and users, enabling the discovery, acquisition, and management of various resources and services within the ThreeFold ecosystem.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FAQ Item 2 -->
|
||||
<div class="accordion-item mb-3">
|
||||
<h2 class="accordion-header" id="faqHeading2">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse2" aria-expanded="false" aria-controls="faqCollapse2">
|
||||
What can I find on the Marketplace?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="faqCollapse2" class="accordion-collapse collapse" aria-labelledby="faqHeading2" data-bs-parent="#faqAccordion">
|
||||
<div class="accordion-body">
|
||||
The Marketplace offers various categories including: Compute Resources (slices) for cloud computing, physical 3Nodes for hardware, Mycelium Gateways for connectivity, self-healing Application Solutions that maintain your data sovereignty, and Human Energy Services where you can access professional expertise.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FAQ Item 3 -->
|
||||
<div class="accordion-item mb-3">
|
||||
<h2 class="accordion-header" id="faqHeading3">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse3" aria-expanded="false" aria-controls="faqCollapse3">
|
||||
How does sovereignty work with self-healing applications?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="faqCollapse3" class="accordion-collapse collapse" aria-labelledby="faqHeading3" data-bs-parent="#faqAccordion">
|
||||
<div class="accordion-body">
|
||||
<p>Unlike traditional SaaS offerings where you surrender control to the provider, ThreeFold's model maintains your sovereignty in two ways:</p>
|
||||
<ol class="mb-3">
|
||||
<li><strong>Direct Management:</strong> Manage your own compute slices directly for complete control</li>
|
||||
<li><strong>Sovereign Allocation:</strong> Allocate your sovereign compute slices to solution providers who deploy and manage applications on your infrastructure</li>
|
||||
</ol>
|
||||
<p>With application solutions, you maintain control because:</p>
|
||||
<ul>
|
||||
<li>You still own and control the underlying resources</li>
|
||||
<li>Your data remains on infrastructure under your control</li>
|
||||
<li>Providers cannot access your data without explicit permission</li>
|
||||
<li>You can revoke management access at any time</li>
|
||||
<li>Applications feature continuous monitoring, automated recovery, backup systems, and security updates</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FAQ Item 4 -->
|
||||
<div class="accordion-item mb-3">
|
||||
<h2 class="accordion-header" id="faqHeading4">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse4" aria-expanded="false" aria-controls="faqCollapse4">
|
||||
What are Credits and how do they work?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="faqCollapse4" class="accordion-collapse collapse" aria-labelledby="faqHeading4" data-bs-parent="#faqAccordion">
|
||||
<div class="accordion-body">
|
||||
Credits are the intuitive USD-based currency system used within the marketplace, where 1 Credit = $1.00 USD. This modern approach makes pricing transparent and easy to understand. Credits facilitate seamless transactions between providers and users, with automatic top-up functionality to ensure uninterrupted service. You can purchase Credits with various payment methods, transfer them to other users, and the system automatically handles conversions for all marketplace transactions.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FAQ Item 5 -->
|
||||
<div class="accordion-item mb-3">
|
||||
<h2 class="accordion-header" id="faqHeading5">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse5" aria-expanded="false" aria-controls="faqCollapse5">
|
||||
How do I get started with the Marketplace?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="faqCollapse5" class="accordion-collapse collapse" aria-labelledby="faqHeading5" data-bs-parent="#faqAccordion">
|
||||
<div class="accordion-body">
|
||||
<p>Getting started is simple with three easy steps:</p>
|
||||
<ol class="mb-3">
|
||||
<li><strong>Create Account:</strong> Create an account and verify your identity</li>
|
||||
<li><strong>Set Up Wallet:</strong> Set up your Credits wallet to participate in marketplace transactions, with optional auto top-up for seamless purchases</li>
|
||||
<li><strong>Explore Marketplace:</strong> Browse available resources, applications, and services</li>
|
||||
</ol>
|
||||
<p>The platform will guide you through the process of selecting, configuring, and deploying your chosen resources or services.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FAQ Item 6 -->
|
||||
<div class="accordion-item mb-3">
|
||||
<h2 class="accordion-header" id="faqHeading6">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse6" aria-expanded="false" aria-controls="faqCollapse6">
|
||||
How does auto top-up work?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="faqCollapse6" class="accordion-collapse collapse" aria-labelledby="faqHeading6" data-bs-parent="#faqAccordion">
|
||||
<div class="accordion-body">
|
||||
Auto top-up ensures you never run out of Credits during important transactions. You can configure a threshold amount (e.g., $10) and a top-up amount (e.g., $25). When your balance falls below the threshold during a purchase, the system automatically adds the specified amount using your preferred payment method. This seamless process means your purchases complete without interruption, and you maintain control with daily and monthly spending limits for security.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FAQ Item 7 -->
|
||||
<div class="accordion-item mb-3">
|
||||
<h2 class="accordion-header" id="faqHeading7">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#faqCollapse7" aria-expanded="false" aria-controls="faqCollapse7">
|
||||
What are the core principles of ThreeFold?
|
||||
</button>
|
||||
</h2>
|
||||
<div id="faqCollapse7" class="accordion-collapse collapse" aria-labelledby="faqHeading7" data-bs-parent="#faqAccordion">
|
||||
<div class="accordion-body">
|
||||
<p>ThreeFold is built on four core principles:</p>
|
||||
<ol>
|
||||
<li><strong>Sovereignty:</strong> Users maintain control over their resources and data</li>
|
||||
<li><strong>Transparency:</strong> Clear pricing and reputation metrics for all marketplace participants</li>
|
||||
<li><strong>Decentralization:</strong> Distributed architecture with no single point of control or failure</li>
|
||||
<li><strong>Community:</strong> Built by and for the community, with fair and inclusive participation</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
// Initialize tooltips
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl)
|
||||
})
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
81
src/views/legal/privacy.html
Normal file
81
src/views/legal/privacy.html
Normal file
@@ -0,0 +1,81 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Privacy Policy - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto legal-content">
|
||||
<h1 class="mb-4">Privacy Policy</h1>
|
||||
<p class="lead mb-4">Last updated: May 20, 2025</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p class="mb-0">Project Mycelium is committed to protecting your privacy and ensuring the security of your personal information.</p>
|
||||
</div>
|
||||
|
||||
<h2>1. Information We Collect</h2>
|
||||
<p>We collect several different types of information for various purposes to provide and improve our service to you:</p>
|
||||
<ul>
|
||||
<li><strong>Personal Data</strong>: While using our service, we may ask you to provide us with certain personally identifiable information that can be used to contact or identify you ("Personal Data"). This may include, but is not limited to:</li>
|
||||
<ul>
|
||||
<li>Email address</li>
|
||||
<li>Your wallet address</li>
|
||||
<li>Usage data and metrics</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
<h2>2. Use of Data</h2>
|
||||
<p>Project Mycelium uses the collected data for various purposes:</p>
|
||||
<ul>
|
||||
<li>To provide and maintain our service</li>
|
||||
<li>To notify you about changes to our service</li>
|
||||
<li>To provide customer support</li>
|
||||
<li>To provide analysis or valuable information so that we can improve the service</li>
|
||||
<li>To monitor the usage of the service</li>
|
||||
<li>To detect, prevent and address technical issues</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Data Storage and Security</h2>
|
||||
<p>Your data is stored on distributed and decentralized infrastructure, maintaining your sovereignty. We implement robust security measures to protect your personal information, including:</p>
|
||||
<ul>
|
||||
<li>Encryption of data in transit and at rest</li>
|
||||
<li>Regular security audits</li>
|
||||
<li>Access controls and authentication</li>
|
||||
<li>Minimization of data collection and retention</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Your Data Protection Rights</h2>
|
||||
<p>Project Mycelium aims to take reasonable steps to allow you to correct, amend, delete, or limit the use of your Personal Data. You have the following rights:</p>
|
||||
<ul>
|
||||
<li><strong>The right to access</strong>: You have the right to request copies of your personal data.</li>
|
||||
<li><strong>The right to rectification</strong>: You have the right to request that we correct any information you believe is inaccurate or complete information you believe is incomplete.</li>
|
||||
<li><strong>The right to erasure</strong>: You have the right to request that we erase your personal data, under certain conditions.</li>
|
||||
<li><strong>The right to restrict processing</strong>: You have the right to request that we restrict the processing of your personal data, under certain conditions.</li>
|
||||
<li><strong>The right to data portability</strong>: You have the right to request that we transfer the data we have collected to another organization, or directly to you, under certain conditions.</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Cookies and Tracking</h2>
|
||||
<p>We use cookies and similar tracking technologies to track activity on our service and hold certain information. Cookies are files with a small amount of data which may include an anonymous unique identifier.</p>
|
||||
|
||||
<h2>6. Service Providers</h2>
|
||||
<p>We may employ third-party companies and individuals for the following reasons:</p>
|
||||
<ul>
|
||||
<li>To facilitate our service</li>
|
||||
<li>To provide the service on our behalf</li>
|
||||
<li>To perform service-related services</li>
|
||||
<li>To assist us in analyzing how our service is used</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Changes to This Privacy Policy</h2>
|
||||
<p>We may update our Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page. You are advised to review this Privacy Policy periodically for any changes.</p>
|
||||
|
||||
<h2>8. Contact Us</h2>
|
||||
<p>If you have any questions about this Privacy Policy, please contact us:</p>
|
||||
<ul>
|
||||
<li>By email: privacy@threefold.io</li>
|
||||
<li>By visiting the contact page on our website</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
102
src/views/legal/terms-farmers.html
Normal file
102
src/views/legal/terms-farmers.html
Normal file
@@ -0,0 +1,102 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Farmers Terms and Conditions - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto legal-content">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/terms">Terms and Conditions</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Farmers</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<i class="bi bi-hdd-rack fs-1 me-3 text-primary"></i>
|
||||
<h1>Farmers Terms and Conditions</h1>
|
||||
</div>
|
||||
<p class="lead mb-4">Last updated: May 22, 2025</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p class="mb-0">These terms specifically apply to Farmers (Resource Providers) on the Project Mycelium who contribute capacity to the ThreeFold Grid.</p>
|
||||
</div>
|
||||
|
||||
<h2>1. Definition of a Farmer</h2>
|
||||
<p>A "Farmer" refers to any individual or entity that connects hardware resources to the ThreeFold Grid, including but not limited to compute nodes (3Nodes), storage capacity, network infrastructure, or other compatible devices that contribute to the ThreeFold Grid's capacity.</p>
|
||||
|
||||
<h2>2. Farmer Responsibilities</h2>
|
||||
<p>As a Farmer on the Project Mycelium, you agree to:</p>
|
||||
<ul>
|
||||
<li>Maintain your connected hardware in good working condition with adequate internet connectivity</li>
|
||||
<li>Ensure your hardware meets the minimum technical requirements specified in the Farming documentation</li>
|
||||
<li>Promptly address any issues that may affect the availability or performance of your contributed resources</li>
|
||||
<li>Provide accurate information about your farming setup, including location, specifications, and uptime capabilities</li>
|
||||
<li>Comply with all applicable laws and regulations in your jurisdiction regarding hosting services and data centers</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Reputation System and Staking</h2>
|
||||
<p>The Project Mycelium employs a reputation system that affects farmer visibility and rewards:</p>
|
||||
<ul>
|
||||
<li>Your reputation score is calculated based on multiple factors including uptime, staked Credits, and performance metrics</li>
|
||||
<li>Staking Credits increases your reputation score and may qualify you for additional benefits</li>
|
||||
<li>Consistent uptime contributes positively to your reputation score</li>
|
||||
<li>Poor performance or extended downtime may result in reputation penalties</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Rewards and Credits</h2>
|
||||
<p>Compensation for resource contribution is governed by the following principles:</p>
|
||||
<ul>
|
||||
<li>Farmers receive USD Credits based on the resources utilized from their contributed capacity</li>
|
||||
<li>Credits have a fixed value of 1.0 USD per Credit</li>
|
||||
<li>Earned Credits can be exchanged for fiat currencies or other supported tokens through the available liquidity pools</li>
|
||||
<li>Payment schedules and minimum thresholds are detailed in the Farmer dashboard</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Hardware and Capacity</h2>
|
||||
<p>Regarding the hardware and capacity you provide:</p>
|
||||
<ul>
|
||||
<li>You retain ownership of all hardware connected to the ThreeFold Grid</li>
|
||||
<li>You are responsible for the electricity, internet connectivity, and physical security of your hardware</li>
|
||||
<li>You have the right to disconnect your hardware at any time, subject to any active resource reservations</li>
|
||||
<li>ThreeFold does not guarantee that your capacity will be utilized by users</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. Slashing Conditions</h2>
|
||||
<p>In certain circumstances, penalties may be applied to your account:</p>
|
||||
<ul>
|
||||
<li>Consistent failure to maintain promised uptime without prior notice</li>
|
||||
<li>Deliberate misrepresentation of hardware specifications or capabilities</li>
|
||||
<li>Violating the terms of service or engaging in fraudulent activities</li>
|
||||
<li>Slashing penalties may include reputation reduction, temporary suspension, or in severe cases, permanent removal from the marketplace</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Termination of Farmer Status</h2>
|
||||
<p>You may cease being a Farmer by:</p>
|
||||
<ul>
|
||||
<li>Disconnecting your hardware from the ThreeFold Grid</li>
|
||||
<li>Providing notice through your dashboard at least 30 days prior to complete disconnection</li>
|
||||
<li>Ensuring all active resource reservations have been properly concluded or migrated</li>
|
||||
</ul>
|
||||
|
||||
<h2>8. Liability Limitation</h2>
|
||||
<p>As a Farmer, you acknowledge that:</p>
|
||||
<ul>
|
||||
<li>ThreeFold is not responsible for any damage to your hardware resulting from normal operation</li>
|
||||
<li>ThreeFold does not guarantee minimum income or utilization rates for your contributed capacity</li>
|
||||
<li>You are solely responsible for compliance with local laws regarding hosting services, taxation, and business operations</li>
|
||||
</ul>
|
||||
|
||||
<div class="alert alert-warning mt-5">
|
||||
<h5 class="alert-heading">Important Note</h5>
|
||||
<p class="mb-0">These Farmer-specific terms are in addition to the <a href="/terms">General Terms and Conditions</a> that apply to all users of the Project Mycelium. Please ensure you have reviewed both documents.</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5 mb-3">
|
||||
<a href="/terms" class="btn btn-outline-primary">Back to Main Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
115
src/views/legal/terms-service-providers.html
Normal file
115
src/views/legal/terms-service-providers.html
Normal file
@@ -0,0 +1,115 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Service Providers Terms and Conditions - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto legal-content">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/terms">Terms and Conditions</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Service Providers</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<i class="bi bi-gear-wide-connected fs-1 me-3 text-success"></i>
|
||||
<h1>Service Providers Terms and Conditions</h1>
|
||||
</div>
|
||||
<p class="lead mb-4">Last updated: May 22, 2025</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p class="mb-0">These terms specifically apply to Service Providers on the Project Mycelium who offer managed services utilizing the ThreeFold Grid's capacity.</p>
|
||||
</div>
|
||||
|
||||
<h2>1. Definition of a Service Provider</h2>
|
||||
<p>A "Service Provider" refers to any individual or entity that offers managed services, technical support, consulting, or other professional services on the Project Mycelium. Service Providers utilize the ThreeFold Grid's infrastructure to deliver their services to users.</p>
|
||||
|
||||
<h2>2. Service Provider Responsibilities</h2>
|
||||
<p>As a Service Provider on the Project Mycelium, you agree to:</p>
|
||||
<ul>
|
||||
<li>Provide accurate descriptions of all services offered</li>
|
||||
<li>Deliver services according to the specifications and timeframes advertised</li>
|
||||
<li>Maintain professional standards of quality and customer service</li>
|
||||
<li>Respond promptly to user inquiries and service requests</li>
|
||||
<li>Set fair and transparent pricing for your services</li>
|
||||
<li>Provide clear service level agreements (SLAs) where applicable</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Reputation System and Staking</h2>
|
||||
<p>The Project Mycelium employs a reputation system that affects service provider visibility and benefits:</p>
|
||||
<ul>
|
||||
<li>Your reputation score is calculated based on user ratings, service delivery performance, and staked Credits</li>
|
||||
<li>Higher reputation scores may result in improved visibility in marketplace listings</li>
|
||||
<li>Staking Credits increases your reputation score and may qualify you for reduced platform fees</li>
|
||||
<li>Poor performance or unresolved disputes may result in reputation penalties</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Service Delivery and Credits</h2>
|
||||
<p>Compensation and payment processes are governed by the following principles:</p>
|
||||
<ul>
|
||||
<li>All transactions on the marketplace use USD Credits as the medium of exchange</li>
|
||||
<li>Credits have a fixed value of 1.0 USD per Credit</li>
|
||||
<li>Service Providers receive Credits from users who purchase their services</li>
|
||||
<li>Earned Credits can be exchanged for fiat currencies or other supported tokens through the available liquidity pools</li>
|
||||
<li>Platform fees may apply to transactions as detailed in your Service Provider dashboard</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Service Listings and Marketing</h2>
|
||||
<p>Regarding your service listings on the marketplace:</p>
|
||||
<ul>
|
||||
<li>You are responsible for creating and maintaining accurate service listings</li>
|
||||
<li>All service descriptions must comply with the Marketplace Content Guidelines</li>
|
||||
<li>False or misleading claims about services are prohibited</li>
|
||||
<li>ThreeFold reserves the right to remove or request modifications to listings that violate guidelines</li>
|
||||
<li>You may utilize marketplace promotional tools to increase the visibility of your services</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. Slashing Conditions</h2>
|
||||
<p>In certain circumstances, penalties may be applied to your account:</p>
|
||||
<ul>
|
||||
<li>Consistent failure to deliver services according to the promised specifications</li>
|
||||
<li>Multiple unresolved user disputes or complaints</li>
|
||||
<li>Violating the terms of service or engaging in fraudulent activities</li>
|
||||
<li>Slashing penalties may include reputation reduction, temporary suspension of listings, or in severe cases, permanent removal from the marketplace</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Dispute Resolution</h2>
|
||||
<p>In the event of disputes with users:</p>
|
||||
<ul>
|
||||
<li>You are encouraged to resolve disputes directly with users when possible</li>
|
||||
<li>The Project Mycelium provides a dispute resolution system for unresolved issues</li>
|
||||
<li>Disputes are reviewed by an independent panel based on evidence provided by both parties</li>
|
||||
<li>Consistent patterns of disputes may affect your reputation score</li>
|
||||
</ul>
|
||||
|
||||
<h2>8. Termination of Service Provider Status</h2>
|
||||
<p>You may cease being a Service Provider by:</p>
|
||||
<ul>
|
||||
<li>Removing all service listings from the marketplace</li>
|
||||
<li>Completing all outstanding service obligations to users</li>
|
||||
<li>Providing notice through your dashboard at least 30 days prior to complete service termination</li>
|
||||
</ul>
|
||||
|
||||
<h2>9. Liability Limitation</h2>
|
||||
<p>As a Service Provider, you acknowledge that:</p>
|
||||
<ul>
|
||||
<li>You are solely responsible for the services you provide to users</li>
|
||||
<li>ThreeFold is not a party to agreements between you and users</li>
|
||||
<li>ThreeFold does not guarantee minimum income or service utilization rates</li>
|
||||
<li>You are solely responsible for compliance with local laws regarding professional services, taxation, and business operations</li>
|
||||
</ul>
|
||||
|
||||
<div class="alert alert-warning mt-5">
|
||||
<h5 class="alert-heading">Important Note</h5>
|
||||
<p class="mb-0">These Service Provider-specific terms are in addition to the <a href="/terms">General Terms and Conditions</a> that apply to all users of the Project Mycelium. Please ensure you have reviewed both documents.</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5 mb-3">
|
||||
<a href="/terms" class="btn btn-outline-success">Back to Main Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
127
src/views/legal/terms-solution-providers.html
Normal file
127
src/views/legal/terms-solution-providers.html
Normal file
@@ -0,0 +1,127 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Solution Providers Terms and Conditions - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto legal-content">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/terms">Terms and Conditions</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Solution Providers</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<i class="bi bi-box-seam fs-1 me-3 text-info"></i>
|
||||
<h1>Solution Providers Terms and Conditions</h1>
|
||||
</div>
|
||||
<p class="lead mb-4">Last updated: May 22, 2025</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p class="mb-0">These terms specifically apply to Solution Providers on the Project Mycelium who develop and deploy applications and solutions on the ThreeFold Grid.</p>
|
||||
</div>
|
||||
|
||||
<h2>1. Definition of a Solution Provider</h2>
|
||||
<p>A "Solution Provider" refers to any individual or entity that develops, deploys, and maintains software applications, platforms, or digital solutions on the Project Mycelium. Solution Providers create the applications and services that run on the ThreeFold Grid's infrastructure.</p>
|
||||
|
||||
<h2>2. Solution Provider Responsibilities</h2>
|
||||
<p>As a Solution Provider on the Project Mycelium, you agree to:</p>
|
||||
<ul>
|
||||
<li>Provide accurate descriptions of your applications and solutions</li>
|
||||
<li>Maintain your deployed solutions with regular updates and security patches</li>
|
||||
<li>Ensure your solutions comply with best practices for security and data protection</li>
|
||||
<li>Provide clear documentation for users of your solutions</li>
|
||||
<li>Respond promptly to technical issues and bug reports</li>
|
||||
<li>Set fair and transparent pricing for your solutions</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Reputation System and Staking</h2>
|
||||
<p>The Project Mycelium employs a reputation system that affects solution provider visibility and benefits:</p>
|
||||
<ul>
|
||||
<li>Your reputation score is calculated based on user ratings, solution performance, security metrics, and staked Credits</li>
|
||||
<li>Higher reputation scores may result in improved visibility in marketplace listings</li>
|
||||
<li>Staking Credits increases your reputation score and may qualify you for reduced platform fees</li>
|
||||
<li>Security vulnerabilities or performance issues may result in reputation penalties</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Intellectual Property Rights</h2>
|
||||
<p>Regarding the intellectual property of your solutions:</p>
|
||||
<ul>
|
||||
<li>You retain all intellectual property rights to your applications and solutions</li>
|
||||
<li>You grant ThreeFold a limited license to display, promote, and facilitate access to your solutions on the marketplace</li>
|
||||
<li>You are responsible for ensuring your solutions do not infringe on third-party intellectual property rights</li>
|
||||
<li>You may choose the appropriate licensing model for your solutions (open source, proprietary, etc.)</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Application Deployment and Credits</h2>
|
||||
<p>The deployment and compensation processes are governed by the following principles:</p>
|
||||
<ul>
|
||||
<li>All transactions on the marketplace use USD Credits as the medium of exchange</li>
|
||||
<li>Credits have a fixed value of 1.0 USD per Credit</li>
|
||||
<li>Solution Providers receive Credits from users who utilize their applications</li>
|
||||
<li>Earned Credits can be exchanged for fiat currencies or other supported tokens through the available liquidity pools</li>
|
||||
<li>Platform fees may apply to transactions as detailed in your Solution Provider dashboard</li>
|
||||
<li>You are responsible for the resource utilization costs of your deployed solutions</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. Solution Listings and Distribution</h2>
|
||||
<p>Regarding your solution listings on the marketplace:</p>
|
||||
<ul>
|
||||
<li>All solution descriptions must comply with the Marketplace Content Guidelines</li>
|
||||
<li>False or misleading claims about solutions are prohibited</li>
|
||||
<li>ThreeFold reserves the right to remove or request modifications to listings that violate guidelines</li>
|
||||
<li>You may utilize marketplace promotional tools to increase the visibility of your solutions</li>
|
||||
<li>You may offer free trials, freemium models, or paid solutions according to your business model</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. API Usage and Integration</h2>
|
||||
<p>When utilizing ThreeFold APIs and integration points:</p>
|
||||
<ul>
|
||||
<li>You must adhere to the API usage guidelines and rate limits</li>
|
||||
<li>You are responsible for updating your integrations when API changes are announced</li>
|
||||
<li>Marketplace API keys must be secured and never exposed publicly</li>
|
||||
<li>ThreeFold provides documentation and support for API integration</li>
|
||||
</ul>
|
||||
|
||||
<h2>8. Slashing Conditions</h2>
|
||||
<p>In certain circumstances, penalties may be applied to your account:</p>
|
||||
<ul>
|
||||
<li>Security vulnerabilities that put user data at risk</li>
|
||||
<li>Consistent performance issues that significantly impact user experience</li>
|
||||
<li>Violations of content guidelines or terms of service</li>
|
||||
<li>Fraudulent activities or misrepresentation of solution capabilities</li>
|
||||
<li>Slashing penalties may include reputation reduction, temporary suspension of listings, or in severe cases, permanent removal from the marketplace</li>
|
||||
</ul>
|
||||
|
||||
<h2>9. Updates and Maintenance</h2>
|
||||
<p>Regarding the ongoing maintenance of your solutions:</p>
|
||||
<ul>
|
||||
<li>You are responsible for providing regular updates and maintenance</li>
|
||||
<li>Critical security updates should be prioritized and deployed promptly</li>
|
||||
<li>Significant changes to functionality should be clearly communicated to users</li>
|
||||
<li>Scheduled maintenance should be announced in advance when possible</li>
|
||||
</ul>
|
||||
|
||||
<h2>10. Termination of Solution Provider Status</h2>
|
||||
<p>You may cease being a Solution Provider by:</p>
|
||||
<ul>
|
||||
<li>Removing all solution listings from the marketplace</li>
|
||||
<li>Providing a reasonable migration path or notice to existing users</li>
|
||||
<li>Completing all outstanding obligations to users</li>
|
||||
<li>Providing notice through your dashboard at least 30 days prior to solution removal</li>
|
||||
</ul>
|
||||
|
||||
<div class="alert alert-warning mt-5">
|
||||
<h5 class="alert-heading">Important Note</h5>
|
||||
<p class="mb-0">These Solution Provider-specific terms are in addition to the <a href="/terms">General Terms and Conditions</a> that apply to all users of the Project Mycelium. Please ensure you have reviewed both documents.</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5 mb-3">
|
||||
<a href="/terms" class="btn btn-outline-info">Back to Main Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
134
src/views/legal/terms-users.html
Normal file
134
src/views/legal/terms-users.html
Normal file
@@ -0,0 +1,134 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Users Terms and Conditions - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 mx-auto legal-content">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/terms">Terms and Conditions</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Users</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<i class="bi bi-person-check fs-1 me-3 text-warning"></i>
|
||||
<h1>Users Terms and Conditions</h1>
|
||||
</div>
|
||||
<p class="lead mb-4">Last updated: May 22, 2025</p>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<p class="mb-0">These terms specifically apply to Users of the Project Mycelium who utilize services, applications, and resources offered on the ThreeFold Grid.</p>
|
||||
</div>
|
||||
|
||||
<h2>1. Definition of a User</h2>
|
||||
<p>A "User" refers to any individual or entity that accesses and utilizes services, applications, resources, or solutions available on the Project Mycelium. Users utilize the ThreeFold Grid's offerings.</p>
|
||||
|
||||
<h2>2. User Account and Registration</h2>
|
||||
<p>Regarding your user account:</p>
|
||||
<ul>
|
||||
<li>You must provide accurate, complete, and up-to-date information during the registration process</li>
|
||||
<li>You are responsible for maintaining the confidentiality of your account credentials</li>
|
||||
<li>You are responsible for all activities that occur under your account</li>
|
||||
<li>You must immediately notify ThreeFold of any unauthorized use of your account</li>
|
||||
<li>ThreeFold reserves the right to suspend or terminate accounts that violate these terms</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Credits System and Payments</h2>
|
||||
<p>The payment and usage system is governed by the following principles:</p>
|
||||
<ul>
|
||||
<li>All transactions on the marketplace use USD Credits as the medium of exchange</li>
|
||||
<li>Credits have a fixed value of 1.0 USD per Credit</li>
|
||||
<li>You can acquire Credits through various methods including fiat currency exchange and token swaps via liquidity pools</li>
|
||||
<li>The more Credits you hold or stake, the higher discounts you may receive on marketplace offerings</li>
|
||||
<li>Payment for services and resources is automatically processed according to your usage</li>
|
||||
<li>Unused Credits remain in your account balance until used or exchanged</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Reputation System and Staking</h2>
|
||||
<p>The Project Mycelium employs a reputation system that benefits users:</p>
|
||||
<ul>
|
||||
<li>Your user reputation score may affect your access to premium services and discount rates</li>
|
||||
<li>Staking Credits increases your reputation score and qualifies you for discounts on services</li>
|
||||
<li>Staking tiers provide increasing benefits:
|
||||
<ul>
|
||||
<li>5% discount: Entry-level staking</li>
|
||||
<li>10% discount: Mid-level staking</li>
|
||||
<li>15% discount: High-level staking</li>
|
||||
<li>20% discount: Premium-level staking</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Staking periods may affect discount rates, with longer commitments providing greater benefits</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Usage Limitations and Fair Use</h2>
|
||||
<p>When using Project Mycelium offerings:</p>
|
||||
<ul>
|
||||
<li>You agree to use resources and services for legitimate purposes only</li>
|
||||
<li>You will not attempt to circumvent any usage limitations or monitoring systems</li>
|
||||
<li>You will not engage in activities that may disrupt or harm the ThreeFold Grid or other users</li>
|
||||
<li>Excessive or abusive usage patterns may result in usage restrictions</li>
|
||||
<li>ThreeFold reserves the right to implement fair use policies for specific services</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. Data and Privacy</h2>
|
||||
<p>Regarding your data on the Project Mycelium:</p>
|
||||
<ul>
|
||||
<li>You retain ownership of all data you store or process using ThreeFold services</li>
|
||||
<li>ThreeFold implements zero-knowledge architecture whenever possible, meaning we cannot access your data</li>
|
||||
<li>You are responsible for complying with applicable data protection laws when processing personal data</li>
|
||||
<li>ThreeFold may collect certain usage metrics for billing and service improvement purposes</li>
|
||||
<li>For complete information on data handling, please review our <a href="/privacy">Privacy Policy</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Service Level Expectations</h2>
|
||||
<p>Regarding service availability and quality:</p>
|
||||
<ul>
|
||||
<li>Project Mycelium is a decentralized platform where service levels may vary by provider</li>
|
||||
<li>Each service, application, or resource has its own specific service level agreement (SLA)</li>
|
||||
<li>ThreeFold promotes transparency in performance metrics to help you make informed choices</li>
|
||||
<li>In case of service issues, you should first contact the specific provider of the service</li>
|
||||
<li>ThreeFold provides a dispute resolution system for unresolved issues with providers</li>
|
||||
</ul>
|
||||
|
||||
<h2>8. Dispute Resolution</h2>
|
||||
<p>In the event of disputes with service providers:</p>
|
||||
<ul>
|
||||
<li>You are encouraged to resolve disputes directly with providers when possible</li>
|
||||
<li>The Project Mycelium provides a dispute resolution system for unresolved issues</li>
|
||||
<li>Disputes are reviewed by an independent panel based on evidence provided by both parties</li>
|
||||
<li>For eligible cases, a refund may be processed in Credits to your account</li>
|
||||
</ul>
|
||||
|
||||
<h2>9. Account Termination</h2>
|
||||
<p>You may terminate your user account by:</p>
|
||||
<ul>
|
||||
<li>Requesting account closure through your dashboard settings</li>
|
||||
<li>Exchanging or withdrawing any remaining Credits balance</li>
|
||||
<li>Ensuring all active services or deployments are properly terminated</li>
|
||||
<li>Removing any personal data you wish to delete before account closure</li>
|
||||
</ul>
|
||||
|
||||
<h2>10. User Feedback and Community Participation</h2>
|
||||
<p>As a Project Mycelium user:</p>
|
||||
<ul>
|
||||
<li>You are encouraged to provide honest feedback on services and resources you utilize</li>
|
||||
<li>Your ratings and reviews help maintain quality standards in the ecosystem</li>
|
||||
<li>You may participate in the ThreeFold community forums and governance processes</li>
|
||||
<li>Constructive feedback helps improve the marketplace for all participants</li>
|
||||
</ul>
|
||||
|
||||
<div class="alert alert-warning mt-5">
|
||||
<h5 class="alert-heading">Important Note</h5>
|
||||
<p class="mb-0">These User-specific terms are in addition to the <a href="/terms">General Terms and Conditions</a> that apply to all users of the Project Mycelium. Please ensure you have reviewed both documents.</p>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5 mb-3">
|
||||
<a href="/terms" class="btn btn-outline-warning">Back to Main Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
132
src/views/legal/terms.html
Normal file
132
src/views/legal/terms.html
Normal file
@@ -0,0 +1,132 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Terms and Conditions - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-10 mx-auto legal-content">
|
||||
<h1 class="mb-4">Terms and Conditions</h1>
|
||||
<p class="lead mb-4">Last updated: May 22, 2025</p>
|
||||
|
||||
<div class="alert alert-info mb-5">
|
||||
<p class="mb-0">Please select your role below to view the specific Terms and Conditions that apply to you:</p>
|
||||
</div>
|
||||
|
||||
<div class="row mb-5 g-4">
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-hdd-rack fs-1 mb-3 text-primary"></i>
|
||||
<h5 class="card-title">Farmers</h5>
|
||||
<p class="card-text">Resource Providers contributing capacity to the ThreeFold Grid</p>
|
||||
<a href="/terms/farmers" class="btn btn-outline-primary mt-3">View Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-gear-wide-connected fs-1 mb-3 text-success"></i>
|
||||
<h5 class="card-title">Service Providers</h5>
|
||||
<p class="card-text">Entities offering managed services on the ThreeFold Grid</p>
|
||||
<a href="/terms/service-providers" class="btn btn-outline-success mt-3">View Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-box-seam fs-1 mb-3 text-info"></i>
|
||||
<h5 class="card-title">Solution Providers</h5>
|
||||
<p class="card-text">Application developers and solutions deployed on the Grid</p>
|
||||
<a href="/terms/solution-providers" class="btn btn-outline-info mt-3">View Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-3">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-person-check fs-1 mb-3 text-warning"></i>
|
||||
<h5 class="card-title">Users</h5>
|
||||
<p class="card-text">End users utilizing services and solutions on the ThreeFold Grid</p>
|
||||
<a href="/terms/users" class="btn btn-outline-warning mt-3">View Terms</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-secondary mb-4">
|
||||
<p class="mb-0">Below are the general Terms and Conditions that apply to all users of the Project Mycelium:</p>
|
||||
</div>
|
||||
|
||||
<h2>1. Acceptance of Terms</h2>
|
||||
<p>By accessing or using the Project Mycelium, you agree to be bound by these Terms of Service and all applicable laws and regulations. If you do not agree with any of these terms, you are prohibited from using or accessing the Project Mycelium.</p>
|
||||
|
||||
<h2>2. Description of Service</h2>
|
||||
<p>The Project Mycelium is a platform that facilitates the exchange of value through the USD Credits system. It connects providers and users, enabling the discovery, acquisition, and management of various resources and services including but not limited to:</p>
|
||||
<ul>
|
||||
<li>Compute Resources (Slices)</li>
|
||||
<li>3Nodes</li>
|
||||
<li>Mycelium Gateways</li>
|
||||
<li>Bandwidth Providers</li>
|
||||
<li>Application Solutions</li>
|
||||
<li>Human Energy Services</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. User Accounts</h2>
|
||||
<p>When you create an account with us, you guarantee that:</p>
|
||||
<ul>
|
||||
<li>You are above the age of 18 and have the legal capacity to enter into binding contracts.</li>
|
||||
<li>The information you provide us is accurate, complete, and current at all times.</li>
|
||||
<li>You are responsible for maintaining the confidentiality of your account information, including password.</li>
|
||||
<li>You accept responsibility for all activities that occur under your account.</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Marketplace Transactions</h2>
|
||||
<p>All transactions conducted through the Project Mycelium are subject to the following conditions:</p>
|
||||
<ul>
|
||||
<li>Transactions are conducted using the USD Credits system.</li>
|
||||
<li>You acknowledge that the prices of resources and services may fluctuate based on market conditions.</li>
|
||||
<li>ThreeFold is not a party to any transaction between users and does not guarantee the quality, safety, or legality of any resources or services offered.</li>
|
||||
<li>You are solely responsible for your transactions and interactions with other users.</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Intellectual Property</h2>
|
||||
<p>The Project Mycelium and its original content, features, and functionality are and will remain the exclusive property of ThreeFold and its licensors. The service is protected by copyright, trademark, and other laws of both the United States and foreign countries.</p>
|
||||
|
||||
<h2>6. User Conduct</h2>
|
||||
<p>You agree not to use the Project Mycelium for any purpose that is unlawful or prohibited by these Terms. You may not:</p>
|
||||
<ul>
|
||||
<li>Use the service in any way that could disable, overburden, damage, or impair the service</li>
|
||||
<li>Use any robot, spider, or other automatic device, process, or means to access the service for any purpose</li>
|
||||
<li>Introduce any viruses, Trojan horses, worms, logic bombs, or other harmful material</li>
|
||||
<li>Attempt to gain unauthorized access to, interfere with, damage, or disrupt any parts of the service</li>
|
||||
<li>Use the service to advertise or offer to sell goods and services except as explicitly allowed by the marketplace features</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Limitation of Liability</h2>
|
||||
<p>In no event shall ThreeFold, its directors, employees, partners, agents, suppliers, or affiliates, be liable for any indirect, incidental, special, consequential or punitive damages, including without limitation, loss of profits, data, use, goodwill, or other intangible losses, resulting from:</p>
|
||||
<ul>
|
||||
<li>Your access to or use of or inability to access or use the service</li>
|
||||
<li>Any conduct or content of any third party on the service</li>
|
||||
<li>Any content obtained from the service</li>
|
||||
<li>Unauthorized access, use, or alteration of your transmissions or content</li>
|
||||
</ul>
|
||||
|
||||
<h2>8. Governing Law</h2>
|
||||
<p>These Terms shall be governed and construed in accordance with the laws of applicable jurisdiction, without regard to its conflict of law provisions.</p>
|
||||
|
||||
<h2>9. Changes to Terms</h2>
|
||||
<p>We reserve the right to modify or replace these Terms at any time. If a revision is material, we will provide at least 30 days' notice prior to any new terms taking effect. What constitutes a material change will be determined at our sole discretion.</p>
|
||||
|
||||
<h2>10. Contact Us</h2>
|
||||
<p>If you have any questions about these Terms, please contact us:</p>
|
||||
<ul>
|
||||
<li>By email: legal@threefold.pro</li>
|
||||
<li>By visiting the contact page on our website</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
303
src/views/marketplace/applications.html
Normal file
303
src/views/marketplace/applications.html
Normal file
@@ -0,0 +1,303 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - Application Solutions{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<h1>Application Solutions</h1>
|
||||
<p class="lead">Discover self-healing applications that maintain sovereignty while offering convenience.</p>
|
||||
|
||||
<!-- Application Solutions Introduction -->
|
||||
<div class="alert alert-info mb-4">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-info-circle-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">How Application Solutions Work</h5>
|
||||
<p>ThreeFold Application Solutions use a unique model: You provide the compute resources (Slices), while solution providers manage the applications. This ensures you maintain sovereignty over your infrastructure while benefiting from professional management.</p>
|
||||
<hr>
|
||||
<p class="mb-0">When you deploy an application, you'll be guided through the process of allocating the necessary resources if you don't already have them.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter and Search Section -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filter Applications</h5>
|
||||
<form class="row g-3" method="GET">
|
||||
<div class="col-md-3">
|
||||
<label for="appTypeFilter" class="form-label">App Type</label>
|
||||
<select name="app_type" id="appTypeFilter" class="form-select">
|
||||
<option value="">All Types</option>
|
||||
<option value="Web">Web Applications</option>
|
||||
<option value="Productivity">Productivity</option>
|
||||
<option value="Development">Development</option>
|
||||
<option value="Database">Database</option>
|
||||
<option value="Communication">Communication</option>
|
||||
<option value="CMS">Content Management</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="deploymentFilter" class="form-label">Deployment Type</label>
|
||||
<select name="deployment_type" id="deploymentFilter" class="form-select">
|
||||
<option value="">Any</option>
|
||||
<option value="Container">Container</option>
|
||||
<option value="VM">Virtual Machine</option>
|
||||
<option value="Kubernetes">Kubernetes</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="minPriceFilter" class="form-label">Min Price ($)</label>
|
||||
<input type="number" name="min_price" id="minPriceFilter" class="form-control"
|
||||
value="" placeholder="0" min="0" step="1">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="maxPriceFilter" class="form-label">Max Price ($)</label>
|
||||
<input type="number" name="max_price" id="maxPriceFilter" class="form-control"
|
||||
value="" placeholder="50" min="0" step="1">
|
||||
</div>
|
||||
<div class="col-md-6 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-primary me-2">Apply Filters</button>
|
||||
<a href="/marketplace/applications" class="btn btn-outline-secondary">Clear</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Applications Grid -->
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4 mb-5">
|
||||
{% if application_products and application_products | length > 0 %}
|
||||
{% for product_data in application_products %}
|
||||
<div class="col">
|
||||
<div class="card h-100">
|
||||
<div class="position-relative p-4 bg-light text-center">
|
||||
<i class="bi bi-app fs-1 text-primary"></i>
|
||||
<span class="position-absolute top-0 end-0 badge bg-primary m-2">{{ product_data.product.category_id | title }}</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<h5 class="card-title">
|
||||
<a href="/products/{{ product_data.product.id }}" class="text-decoration-none text-dark">
|
||||
{{ product_data.product.name }}
|
||||
</a>
|
||||
</h5>
|
||||
{% if product_data.product.metadata.featured %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% elif product_data.product.availability == "Available" %}
|
||||
<span class="badge bg-success">Available</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ product_data.product.availability }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="card-text">{{ product_data.product.description | truncate(length=100) }}</p>
|
||||
|
||||
<!-- Features (from tags) -->
|
||||
{% if product_data.product.metadata.tags and product_data.product.metadata.tags | length > 0 %}
|
||||
<div class="mb-3">
|
||||
<h6 class="mb-2">Features:</h6>
|
||||
<div class="d-flex flex-wrap">
|
||||
{% for tag in product_data.product.metadata.tags %}
|
||||
<span class="badge bg-light text-dark me-1 mb-1">{{ tag | title }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Resource Requirements -->
|
||||
{% if product_data.product.attributes %}
|
||||
<div class="mb-3">
|
||||
<h6 class="mb-2">Resource Requirements:</h6>
|
||||
<div class="d-flex">
|
||||
{% if product_data.product.attributes.cpu_cores %}
|
||||
<div class="me-3"><i class="bi bi-cpu me-1"></i> {{ product_data.product.attributes.cpu_cores.value }} cores</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.memory_gb %}
|
||||
<div class="me-3"><i class="bi bi-memory me-1"></i> {{ product_data.product.attributes.memory_gb.value }} GB</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.storage_gb %}
|
||||
<div><i class="bi bi-hdd me-1"></i> {{ product_data.product.attributes.storage_gb.value }} GB</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Provider Info -->
|
||||
<div class="mb-3">
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-building me-1"></i>{{ product_data.product.provider_name }}
|
||||
{% if product_data.product.metadata.location %}
|
||||
<span class="ms-2">
|
||||
<i class="bi bi-geo-alt me-1"></i>{{ product_data.product.metadata.location }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="price-info">
|
||||
<span class="text-muted small">Management fee:</span>
|
||||
<div class="fw-bold text-primary">{{ product_data.formatted_price }}</div>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-success btn-sm buy-now-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}"
|
||||
data-category="applications">
|
||||
<i class="bi bi-lightning-fill me-1"></i>Buy Now
|
||||
</button>
|
||||
<button class="btn btn-outline-primary btn-sm add-to-cart-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus me-1"></i>Add to Cart
|
||||
</button>
|
||||
<a href="/products/{{ product_data.product.id }}" class="btn btn-outline-secondary btn-sm">View Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-app display-1 text-muted"></i>
|
||||
<h4 class="mt-3">No Applications Available</h4>
|
||||
<p class="text-muted">Check back later for new application solutions.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if pagination and pagination.total_pages > 1 %}
|
||||
<nav aria-label="Application pages" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<!-- Previous Page -->
|
||||
<li class="page-item {% if not pagination.has_previous %}disabled{% endif %}">
|
||||
{% if pagination.has_previous %}
|
||||
<a class="page-link" href="?page={{ pagination.previous_page }}">Previous</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Previous</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 1 -->
|
||||
<li class="page-item {% if pagination.current_page == 0 %}active{% endif %}">
|
||||
{% if pagination.current_page == 0 %}
|
||||
<span class="page-link">1</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=0">1</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 2 (if exists) -->
|
||||
{% if pagination.total_pages > 1 %}
|
||||
<li class="page-item {% if pagination.current_page == 1 %}active{% endif %}">
|
||||
{% if pagination.current_page == 1 %}
|
||||
<span class="page-link">2</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=1">2</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 3 (if exists) -->
|
||||
{% if pagination.total_pages > 2 %}
|
||||
<li class="page-item {% if pagination.current_page == 2 %}active{% endif %}">
|
||||
{% if pagination.current_page == 2 %}
|
||||
<span class="page-link">3</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=2">3</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 4 (if exists) -->
|
||||
{% if pagination.total_pages > 3 %}
|
||||
<li class="page-item {% if pagination.current_page == 3 %}active{% endif %}">
|
||||
{% if pagination.current_page == 3 %}
|
||||
<span class="page-link">4</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=3">4</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 5 (if exists) -->
|
||||
{% if pagination.total_pages > 4 %}
|
||||
<li class="page-item {% if pagination.current_page == 4 %}active{% endif %}">
|
||||
{% if pagination.current_page == 4 %}
|
||||
<span class="page-link">5</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=4">5</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Next Page -->
|
||||
<li class="page-item {% if not pagination.has_next %}disabled{% endif %}">
|
||||
{% if pagination.has_next %}
|
||||
<a class="page-link" href="?page={{ pagination.next_page }}">Next</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Next</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Results Info -->
|
||||
<div class="text-center text-muted mt-2">
|
||||
Showing page {{ pagination.current_page + 1 }} of {{ pagination.total_pages }}
|
||||
({{ pagination.total_count }} total applications)
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- How It Works Section -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">How Application Deployment Works</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h5>1. Choose Your Application</h5>
|
||||
<p>Browse our catalog of self-healing applications and select the one that meets your needs.</p>
|
||||
|
||||
<h5>2. Resource Allocation</h5>
|
||||
<p>We'll guide you through allocating the necessary compute resources (Slices) for your application.</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h5>3. Deployment & Management</h5>
|
||||
<p>The solution provider handles deployment, updates, and maintenance while you retain full sovereignty.</p>
|
||||
|
||||
<h5>4. Access & Control</h5>
|
||||
<p>Access your application through secure channels while maintaining complete control over your data and infrastructure.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success mt-3">
|
||||
<i class="bi bi-shield-check me-2"></i>
|
||||
<strong>Your Sovereignty Guaranteed:</strong> You own the infrastructure, we provide the expertise. Your data never leaves your control.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.price-info {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
border-top: 1px solid rgba(0,0,0,.125);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="/static/js/marketplace-category.js"></script>
|
||||
|
||||
{% endblock %}
|
||||
410
src/views/marketplace/cart.html
Normal file
410
src/views/marketplace/cart.html
Normal file
@@ -0,0 +1,410 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
{% block title %}Shopping Cart - Project Mycelium{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.hover-shadow:hover {
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.add-recommended-btn {
|
||||
transition: all 0.2s ease;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.add-recommended-btn:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2"><i class="bi bi-cart3 me-2"></i>Shopping Cart</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group me-2">
|
||||
<a href="/marketplace" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>Continue Shopping
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if cart.is_empty %}
|
||||
<!-- Empty Cart State -->
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8 text-center">
|
||||
<div class="card border-0">
|
||||
<div class="card-body py-5">
|
||||
<i class="bi bi-cart-x display-1 text-muted mb-4"></i>
|
||||
<h3 class="text-muted mb-3">Your cart is empty</h3>
|
||||
<p class="text-muted mb-4">Looks like you haven't added any items to your cart yet. Browse our marketplace to find the perfect ThreeFold resources for your needs.</p>
|
||||
<a href="/marketplace" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-shop me-2"></i>Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<!-- Cart with Items -->
|
||||
<div class="row">
|
||||
<!-- Cart Items -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">Cart Items ({{ cart.item_count }})</h5>
|
||||
<button class="btn btn-sm btn-outline-danger" id="clearCartBtn">
|
||||
<i class="bi bi-trash me-1"></i>Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
{% for item in cart.items %}
|
||||
<div class="cart-item border-bottom p-4" data-product-id="{{ item.product_id }}">
|
||||
<div class="row align-items-center">
|
||||
<!-- Product Info -->
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 60px; height: 60px;">
|
||||
{% if item.product_category == "compute" %}
|
||||
<i class="bi bi-cpu fs-4 text-primary"></i>
|
||||
{% elif item.product_category == "hardware" %}
|
||||
<i class="bi bi-hdd-rack fs-4 text-success"></i>
|
||||
{% elif item.product_category == "gateways" %}
|
||||
<i class="bi bi-globe fs-4 text-info"></i>
|
||||
{% elif item.product_category == "applications" %}
|
||||
<i class="bi bi-app fs-4 text-warning"></i>
|
||||
{% elif item.product_category == "services" %}
|
||||
<i class="bi bi-person-workspace fs-4 text-secondary"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-box fs-4 text-muted"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-1">{{ item.product_name }}</h6>
|
||||
<p class="text-muted mb-1 small">{{ item.provider_name }}</p>
|
||||
<span class="badge bg-light text-dark">{{ item.product_category|title }}</span>
|
||||
|
||||
{% if item.specifications %}
|
||||
<div class="mt-2">
|
||||
<small class="text-muted">Specifications:</small>
|
||||
<div class="mt-1">
|
||||
{% for key, value in item.specifications %}
|
||||
<span class="badge bg-secondary me-1">{{ key }}: {{ value }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quantity Controls -->
|
||||
<div class="col-md-3">
|
||||
<div class="d-flex align-items-center justify-content-center">
|
||||
<button class="btn btn-sm btn-outline-secondary" data-product-id="{{ item.product_id }}" data-action="decrease">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
<span class="mx-3 fw-bold">{{ item.quantity }}</span>
|
||||
<button class="btn btn-sm btn-outline-secondary" data-product-id="{{ item.product_id }}" data-action="increase">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Price and Actions -->
|
||||
<div class="col-md-3">
|
||||
<div class="text-end">
|
||||
<div class="mb-2">
|
||||
<small class="text-muted">Unit: {{ item.unit_price }}</small>
|
||||
</div>
|
||||
<div class="fw-bold text-primary mb-2">{{ item.total_price }}</div>
|
||||
<button class="btn btn-sm btn-outline-danger" data-product-id="{{ item.product_id }}" data-action="remove">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Summary -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card sticky-top" style="top: 100px;">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Order Summary</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Currency Selector -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted">Display Currency</label>
|
||||
<select class="form-select form-select-sm" id="currencySelector">
|
||||
{% for currency in currencies %}
|
||||
<option value="{{ currency.code }}" {% if currency.code == user_currency %}selected{% endif %}>
|
||||
{{ currency.symbol }} {{ currency.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Price Breakdown -->
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal ({{ cart.item_count }} items)</span>
|
||||
<span>{{ cart.subtotal }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Estimated fees</span>
|
||||
<span class="text-muted">Calculated at checkout</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span class="fw-bold">Total</span>
|
||||
<span class="fw-bold text-primary fs-5">{{ cart.total }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Guest User Notice -->
|
||||
{% if not user_json %}
|
||||
<div class="alert alert-info mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<div>
|
||||
<strong>Almost ready to checkout!</strong><br>
|
||||
<small>You'll need to log in or create an account to complete your purchase. Don't worry - your cart items will be saved!</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Checkout Button -->
|
||||
<div class="d-grid">
|
||||
{% if user_json %}
|
||||
<a href="/checkout" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-credit-card me-2"></i>Proceed to Checkout
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="btn btn-primary btn-lg" data-bs-toggle="modal" data-bs-target="#guestCheckoutModal">
|
||||
<i class="bi bi-credit-card me-2"></i>Proceed to Checkout
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Security Notice -->
|
||||
<div class="mt-3 p-3 bg-light rounded">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-shield-check text-success me-2"></i>
|
||||
<small class="text-muted">Secure checkout with 256-bit SSL encryption</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recommended Products -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0"><i class="bi bi-stars me-2"></i>Recommended for you</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-2">
|
||||
{% for product_data in recommended_products %}
|
||||
<div class="col-12">
|
||||
<div class="d-flex align-items-center p-3 border rounded hover-shadow" style="transition: all 0.2s ease;">
|
||||
<i class="bi bi-cpu text-primary me-3 fs-4"></i>
|
||||
<div class="flex-grow-1">
|
||||
<div class="fw-bold">{{ product_data.product.name }}</div>
|
||||
<small class="text-muted">{{ product_data.product.description }}</small>
|
||||
<div class="text-primary fw-bold mt-1">{{ product_data.formatted_price }}</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary add-recommended-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-product-price="{{ product_data.price.display_amount }}"
|
||||
data-product-category="{{ product_data.product.category_id }}">
|
||||
<i class="bi bi-plus me-1"></i>Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<a href="/marketplace" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-shop me-1"></i>Browse All Products
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Clear Cart Confirmation Modal -->
|
||||
<div class="modal fade" id="clearCartModal" tabindex="-1" aria-labelledby="clearCartModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title" id="clearCartModalLabel">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>Clear Entire Cart
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-cart-x text-danger me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<p class="mb-1 fw-bold">Are you sure you want to clear your entire cart?</p>
|
||||
<p class="mb-0 text-muted small">This action will remove all items from your cart and cannot be undone.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-warning d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<small>All {{ cart.item_count }} items will be permanently removed from your cart.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x-circle me-1"></i>Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmClearCartBtn">
|
||||
<i class="bi bi-trash me-1"></i>Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Remove Item Confirmation Modal -->
|
||||
<div class="modal fade" id="removeItemModal" tabindex="-1" aria-labelledby="removeItemModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning text-dark">
|
||||
<h5 class="modal-title" id="removeItemModalLabel">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>Remove Item
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-trash text-warning me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<p class="mb-1 fw-bold">Remove this item from your cart?</p>
|
||||
<p class="mb-0 text-muted small">This action cannot be undone.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<small>You can always add this item back later from the marketplace.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x-circle me-1"></i>Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning" id="confirmRemoveItemBtn">
|
||||
<i class="bi bi-trash me-1"></i>Remove Item
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div id="loadingOverlay" class="position-fixed top-0 start-0 w-100 h-100 d-none" style="background: rgba(0,0,0,0.5); z-index: 9999;">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<div class="spinner-border text-light" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="/static/js/cart-marketplace.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
<!-- Guest Checkout Modal -->
|
||||
<div class="modal fade" id="guestCheckoutModal" tabindex="-1" aria-labelledby="guestCheckoutModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="guestCheckoutModalLabel">
|
||||
<i class="bi bi-person-check me-2"></i>Complete Your Purchase
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="text-center mb-4">
|
||||
<i class="bi bi-cart-check text-primary" style="font-size: 3rem;"></i>
|
||||
<h4 class="mt-3 mb-2">Almost there!</h4>
|
||||
<p class="text-muted">You're just one step away from completing your purchase.</p>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info d-flex align-items-center mb-4">
|
||||
<i class="bi bi-shield-check me-2"></i>
|
||||
<div>
|
||||
<strong>Your cart is safe!</strong><br>
|
||||
<small>All items in your cart will be automatically saved when you log in or create an account.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<h6 class="mb-3">Choose an option to continue:</h6>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 border-primary">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-person-fill text-primary mb-2" style="font-size: 2rem;"></i>
|
||||
<h6>Already have an account?</h6>
|
||||
<p class="text-muted small mb-3">Sign in to access your saved information and complete checkout quickly.</p>
|
||||
<button type="button" class="btn btn-primary w-100" id="guestLoginBtn">
|
||||
<i class="bi bi-box-arrow-in-right me-2"></i>Log In
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 border-success">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-person-plus-fill text-success mb-2" style="font-size: 2rem;"></i>
|
||||
<h6>New to ThreeFold?</h6>
|
||||
<p class="text-muted small mb-3">Create a free account to manage your orders and access exclusive features.</p>
|
||||
<button type="button" class="btn btn-success w-100" id="guestRegisterBtn">
|
||||
<i class="bi bi-person-plus me-2"></i>Create Account
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 p-3 bg-light rounded">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<i class="bi bi-lightning-charge text-warning" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h6 class="mb-1">Quick & Secure</h6>
|
||||
<small class="text-muted">Registration takes less than 30 seconds. Your payment information is protected with enterprise-grade security.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-arrow-left me-2"></i>Continue Shopping
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
499
src/views/marketplace/cart_full.html
Normal file
499
src/views/marketplace/cart_full.html
Normal file
@@ -0,0 +1,499 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Shopping Cart - Project Mycelium{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<!-- Add Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css">
|
||||
|
||||
<style>
|
||||
.cart-item {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.cart-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.quantity-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.quantity-controls button {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.product-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.cart-summary {
|
||||
position: sticky;
|
||||
top: 100px;
|
||||
}
|
||||
|
||||
.security-notice {
|
||||
background: linear-gradient(135deg, #d1ecf1 0%, #bee5eb 100%);
|
||||
border: 1px solid #b6d4da;
|
||||
}
|
||||
|
||||
.empty-cart-icon {
|
||||
font-size: 4rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.toast {
|
||||
z-index: 10000;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/marketplace">Marketplace</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Shopping Cart</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2"><i class="bi bi-cart3 me-2 text-primary"></i>Shopping Cart</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group me-2">
|
||||
<a href="/marketplace" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>Continue Shopping
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if cart.is_empty %}
|
||||
<!-- Empty Cart State -->
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8 text-center">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body py-5">
|
||||
<i class="bi bi-cart-x empty-cart-icon mb-4"></i>
|
||||
<h3 class="text-muted mb-3">Your cart is empty</h3>
|
||||
<p class="text-muted mb-4">Looks like you haven't added any items to your cart yet. Browse our marketplace to find the perfect ThreeFold resources for your needs.</p>
|
||||
<a href="/marketplace" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-shop me-2"></i>Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<!-- Cart with Items -->
|
||||
<div class="row">
|
||||
<!-- Cart Items -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0"><i class="bi bi-bag me-2"></i>Cart Items ({{ cart.item_count }})</h5>
|
||||
<button class="btn btn-sm btn-outline-danger" id="clearCartBtn">
|
||||
<i class="bi bi-trash me-1"></i>Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
{% for item in cart.items %}
|
||||
<div class="cart-item border-bottom p-4" data-product-id="{{ item.product_id }}">
|
||||
<div class="row align-items-center">
|
||||
<!-- Product Info -->
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<div class="product-icon">
|
||||
{% if item.product_category == "compute" %}
|
||||
<i class="bi bi-cpu fs-4 text-primary"></i>
|
||||
{% elif item.product_category == "hardware" %}
|
||||
<i class="bi bi-hdd-rack fs-4 text-success"></i>
|
||||
{% elif item.product_category == "gateways" %}
|
||||
<i class="bi bi-globe fs-4 text-info"></i>
|
||||
{% elif item.product_category == "applications" %}
|
||||
<i class="bi bi-app fs-4 text-warning"></i>
|
||||
{% elif item.product_category == "services" %}
|
||||
<i class="bi bi-person-workspace fs-4 text-secondary"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-box fs-4 text-muted"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-1 fw-bold">{{ item.product_name }}</h6>
|
||||
<p class="text-muted mb-1 small">
|
||||
<i class="bi bi-building me-1"></i>{{ item.provider_name }}
|
||||
</p>
|
||||
<span class="badge bg-light text-dark border">
|
||||
<i class="bi bi-tag me-1"></i>{{ item.product_category|title }}
|
||||
</span>
|
||||
|
||||
{% if item.specifications %}
|
||||
<div class="mt-2">
|
||||
<small class="text-muted fw-bold">Specifications:</small>
|
||||
<div class="mt-1">
|
||||
{% for key, value in item.specifications %}
|
||||
<span class="badge bg-secondary me-1 small">{{ key }}: {{ value }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quantity Controls -->
|
||||
<div class="col-md-3">
|
||||
<div class="quantity-controls justify-content-center">
|
||||
<button class="btn btn-sm btn-outline-secondary" data-product-id="{{ item.product_id }}" data-action="decrease">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
<span class="mx-3 fw-bold fs-5">{{ item.quantity }}</span>
|
||||
<button class="btn btn-sm btn-outline-secondary" data-product-id="{{ item.product_id }}" data-action="increase">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-center mt-2">
|
||||
<small class="text-muted">Quantity</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Price and Actions -->
|
||||
<div class="col-md-3">
|
||||
<div class="text-end">
|
||||
<div class="mb-2">
|
||||
<small class="text-muted">Unit: {{ item.unit_price }}</small>
|
||||
</div>
|
||||
<div class="fw-bold text-primary mb-3 fs-5">{{ item.total_price }}</div>
|
||||
<button class="btn btn-sm btn-outline-danger" data-product-id="{{ item.product_id }}" data-action="remove" title="Remove item">
|
||||
<i class="bi bi-trash"></i> Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Summary -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow-sm cart-summary">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-receipt me-2"></i>Order Summary</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<!-- Currency Selector -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted fw-bold">
|
||||
<i class="bi bi-currency-exchange me-1"></i>Display Currency
|
||||
</label>
|
||||
<select class="form-select form-select-sm" id="currencySelector">
|
||||
{% for currency in currencies %}
|
||||
<option value="{{ currency.code }}" {% if currency.code == user_currency %}selected{% endif %}>
|
||||
{{ currency.symbol }} {{ currency.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Price Breakdown -->
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span><i class="bi bi-bag me-1"></i>Subtotal ({{ cart.item_count }} items)</span>
|
||||
<span class="fw-bold">{{ cart.subtotal }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted"><i class="bi bi-calculator me-1"></i>Estimated fees</span>
|
||||
<span class="text-muted">Calculated at checkout</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted"><i class="bi bi-truck me-1"></i>Deployment</span>
|
||||
<span class="text-success">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between mb-3">
|
||||
<span class="fw-bold fs-5">Total</span>
|
||||
<span class="fw-bold text-primary fs-4">{{ cart.total }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Checkout Button -->
|
||||
<div class="d-grid mb-3">
|
||||
{% if user_json %}
|
||||
<a href="/checkout" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-credit-card me-2"></i>Proceed to Checkout
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="btn btn-primary btn-lg" data-bs-toggle="modal" data-bs-target="#guestCheckoutModal">
|
||||
<i class="bi bi-credit-card me-2"></i>Proceed to Checkout
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Additional Actions -->
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-outline-secondary btn-sm" data-action="save-for-later">
|
||||
<i class="bi bi-bookmark me-1"></i>Save for Later
|
||||
</button>
|
||||
<button class="btn btn-outline-info btn-sm" data-action="share-cart">
|
||||
<i class="bi bi-share me-1"></i>Share Cart
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Security Notice -->
|
||||
<div class="mt-3 p-3 security-notice rounded">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-shield-check text-success me-2 fs-5"></i>
|
||||
<div>
|
||||
<small class="fw-bold">Secure Checkout</small>
|
||||
<div class="small text-muted">256-bit SSL encryption</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recommended Products -->
|
||||
<div class="card shadow-sm mt-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0"><i class="bi bi-lightbulb me-2"></i>You might also like</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-2">
|
||||
<div class="col-12">
|
||||
<div class="d-flex align-items-center p-3 border rounded hover-shadow">
|
||||
<i class="bi bi-cpu text-primary me-3 fs-4"></i>
|
||||
<div class="flex-grow-1">
|
||||
<div class="fw-bold small">High-Performance Compute</div>
|
||||
<div class="text-muted" style="font-size: 0.75rem;">Starting at $5/month</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="d-flex align-items-center p-3 border rounded hover-shadow">
|
||||
<i class="bi bi-hdd-rack text-success me-3 fs-4"></i>
|
||||
<div class="flex-grow-1">
|
||||
<div class="fw-bold small">Storage Solutions</div>
|
||||
<div class="text-muted" style="font-size: 0.75rem;">Starting at $2.50/month</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="d-flex align-items-center p-3 border rounded hover-shadow">
|
||||
<i class="bi bi-globe text-info me-3 fs-4"></i>
|
||||
<div class="flex-grow-1">
|
||||
<div class="fw-bold small">Gateway Services</div>
|
||||
<div class="text-muted" style="font-size: 0.75rem;">Starting at $1.50/month</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Clear Cart Confirmation Modal -->
|
||||
<div class="modal fade" id="clearCartModal" tabindex="-1" aria-labelledby="clearCartModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title" id="clearCartModalLabel">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>Clear Entire Cart
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-cart-x text-danger me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<p class="mb-1 fw-bold">Are you sure you want to clear your entire cart?</p>
|
||||
<p class="mb-0 text-muted small">This action will remove all items from your cart and cannot be undone.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-warning d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<small>All {{ cart.item_count }} items will be permanently removed from your cart.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x-circle me-1"></i>Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmClearCartBtn">
|
||||
<i class="bi bi-trash me-1"></i>Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Remove Item Confirmation Modal -->
|
||||
<div class="modal fade" id="removeItemModal" tabindex="-1" aria-labelledby="removeItemModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning text-dark">
|
||||
<h5 class="modal-title" id="removeItemModalLabel">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>Remove Item
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-trash text-warning me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<p class="mb-1 fw-bold">Remove this item from your cart?</p>
|
||||
<p class="mb-0 text-muted small">This action cannot be undone.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<small>You can always add this item back later from the marketplace.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x-circle me-1"></i>Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning" id="confirmRemoveItemBtn">
|
||||
<i class="bi bi-trash me-1"></i>Remove Item
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div id="loadingOverlay" class="position-fixed top-0 start-0 w-100 h-100 d-none loading-overlay">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<div class="spinner-border text-light" role="status" style="width: 3rem; height: 3rem;">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type="application/json" id="cart-hydration">
|
||||
{
|
||||
"item_count": {{ cart.item_count }},
|
||||
"redirect_login_url": "/login?checkout=true",
|
||||
"redirect_register_url": "/register?checkout=true",
|
||||
"redirect_after_auth": "/cart"
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/cart.js"></script>
|
||||
|
||||
<!-- Guest Checkout Modal -->
|
||||
<div class="modal fade" id="guestCheckoutModal" tabindex="-1" aria-labelledby="guestCheckoutModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="guestCheckoutModalLabel">
|
||||
<i class="bi bi-person-check me-2"></i>Complete Your Purchase
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="text-center mb-4">
|
||||
<i class="bi bi-cart-check text-primary" style="font-size: 3rem;"></i>
|
||||
<h4 class="mt-3 mb-2">Almost there!</h4>
|
||||
<p class="text-muted">You're just one step away from completing your purchase.</p>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info d-flex align-items-center mb-4">
|
||||
<i class="bi bi-shield-check me-2"></i>
|
||||
<div>
|
||||
<strong>Your cart is safe!</strong><br>
|
||||
<small>All items in your cart will be automatically saved when you log in or create an account.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<h6 class="mb-3">Choose an option to continue:</h6>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 border-primary">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-person-fill text-primary mb-2" style="font-size: 2rem;"></i>
|
||||
<h6>Already have an account?</h6>
|
||||
<p class="text-muted small mb-3">Sign in to access your saved information and complete checkout quickly.</p>
|
||||
<button type="button" class="btn btn-primary w-100" id="guestLoginBtn">
|
||||
<i class="bi bi-box-arrow-in-right me-2"></i>Log In
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 border-success">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-person-plus-fill text-success mb-2" style="font-size: 2rem;"></i>
|
||||
<h6>New to ThreeFold?</h6>
|
||||
<p class="text-muted small mb-3">Create a free account to manage your orders and access exclusive features.</p>
|
||||
<button type="button" class="btn btn-success w-100" id="guestRegisterBtn">
|
||||
<i class="bi bi-person-plus me-2"></i>Create Account
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 p-3 bg-light rounded">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<i class="bi bi-lightning-charge text-warning" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h6 class="mb-1">Quick & Secure</h6>
|
||||
<small class="text-muted">Registration takes less than 30 seconds. Your payment information is protected with enterprise-grade security.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-arrow-left me-2"></i>Continue Shopping
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
18
src/views/marketplace/cart_simple.html
Normal file
18
src/views/marketplace/cart_simple.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Shopping Cart - Project Mycelium{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="container-fluid py-4">
|
||||
<h1>Shopping Cart</h1>
|
||||
<p>Cart page is working!</p>
|
||||
|
||||
{% if cart %}
|
||||
<p>Cart data is available</p>
|
||||
<p>Items: {{ cart.item_count }}</p>
|
||||
<p>Currency: {{ cart.currency }}</p>
|
||||
{% else %}
|
||||
<p>No cart data available</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
573
src/views/marketplace/cart_standalone.html
Normal file
573
src/views/marketplace/cart_standalone.html
Normal file
@@ -0,0 +1,573 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Shopping Cart - Project Mycelium</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.cart-item {
|
||||
transition: all 0.3s ease;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.cart-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.product-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||||
border-radius: 12px;
|
||||
border: 2px solid #dee2e6;
|
||||
}
|
||||
|
||||
.quantity-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.quantity-controls button {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.cart-summary {
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.security-notice {
|
||||
background: linear-gradient(135deg, #d1ecf1 0%, #bee5eb 100%);
|
||||
border: 1px solid #b6d4da;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.empty-cart-icon {
|
||||
font-size: 4rem;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.badge {
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.hover-shadow:hover {
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important;
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.add-recommended-btn {
|
||||
transition: all 0.2s ease;
|
||||
min-width: 60px;
|
||||
}
|
||||
|
||||
.add-recommended-btn:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hover-shadow:hover {
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||
transform: translateY(-1px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>Project Mycelium</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/marketplace">
|
||||
<i class="bi bi-shop me-1"></i>Marketplace
|
||||
</a>
|
||||
<a class="nav-link active" href="/cart">
|
||||
<i class="bi bi-cart3 me-1"></i>Cart
|
||||
</a>
|
||||
<a class="nav-link" href="/orders" id="myOrdersLink" style="display: none;">
|
||||
<i class="bi bi-list-ul me-1"></i>My Orders
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/marketplace" class="text-decoration-none">Marketplace</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Shopping Cart</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-4 border-bottom">
|
||||
<h1 class="h2 mb-0">
|
||||
<i class="bi bi-cart3 me-2 text-primary"></i>Shopping Cart
|
||||
</h1>
|
||||
<div class="btn-toolbar">
|
||||
<a href="/marketplace" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>Continue Shopping
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if cart.is_empty %}
|
||||
<!-- Empty Cart State -->
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8 text-center">
|
||||
<div class="card">
|
||||
<div class="card-body py-5">
|
||||
<i class="bi bi-cart-x empty-cart-icon mb-4"></i>
|
||||
<h3 class="text-muted mb-3">Your cart is empty</h3>
|
||||
<p class="text-muted mb-4">
|
||||
Discover amazing ThreeFold resources and services. From compute power to storage solutions,
|
||||
find everything you need to build on the decentralized internet.
|
||||
</p>
|
||||
<a href="/marketplace" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-shop me-2"></i>Explore Marketplace
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<!-- Cart with Items -->
|
||||
<div class="row">
|
||||
<!-- Cart Items -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-bag me-2"></i>Cart Items
|
||||
<span class="badge bg-primary">{{ cart.item_count }}</span>
|
||||
</h5>
|
||||
<button class="btn btn-sm btn-outline-danger" id="clearCartBtn">
|
||||
<i class="bi bi-trash me-1"></i>Clear All
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
{% for item in cart.items %}
|
||||
<div class="cart-item p-4 border-bottom" data-product-id="{{ item.product_id }}">
|
||||
<div class="row align-items-center">
|
||||
<!-- Product Info -->
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex">
|
||||
<div class="flex-shrink-0 me-3">
|
||||
<div class="product-icon">
|
||||
{% if item.product_category == "compute" %}
|
||||
<i class="bi bi-cpu fs-4 text-primary"></i>
|
||||
{% elif item.product_category == "hardware" %}
|
||||
<i class="bi bi-hdd-rack fs-4 text-success"></i>
|
||||
{% elif item.product_category == "gateways" %}
|
||||
<i class="bi bi-globe fs-4 text-info"></i>
|
||||
{% elif item.product_category == "applications" %}
|
||||
<i class="bi bi-app fs-4 text-warning"></i>
|
||||
{% elif item.product_category == "services" %}
|
||||
<i class="bi bi-person-workspace fs-4 text-secondary"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-box fs-4 text-muted"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-1 fw-bold">{{ item.product_name }}</h6>
|
||||
<p class="text-muted mb-2 small">
|
||||
<i class="bi bi-building me-1"></i>{{ item.provider_name }}
|
||||
</p>
|
||||
<span class="badge bg-light text-dark border">
|
||||
{{ item.product_category|title }}
|
||||
</span>
|
||||
|
||||
{% if item.specifications %}
|
||||
<div class="mt-2">
|
||||
<small class="text-muted fw-bold">Configuration:</small>
|
||||
<div class="mt-1">
|
||||
{% for key, value in item.specifications %}
|
||||
<span class="badge bg-secondary me-1 small">{{ key }}: {{ value }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quantity Controls -->
|
||||
<div class="col-md-3">
|
||||
<div class="quantity-controls justify-content-center">
|
||||
<button class="btn btn-sm btn-outline-secondary" data-product-id="{{ item.product_id }}" data-action="decrease">
|
||||
<i class="bi bi-dash"></i>
|
||||
</button>
|
||||
<span class="mx-3 fw-bold fs-5">{{ item.quantity }}</span>
|
||||
<button class="btn btn-sm btn-outline-secondary" data-product-id="{{ item.product_id }}" data-action="increase">
|
||||
<i class="bi bi-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-center mt-2">
|
||||
<small class="text-muted">Quantity</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Price and Actions -->
|
||||
<div class="col-md-3">
|
||||
<div class="text-end">
|
||||
<div class="mb-2">
|
||||
<small class="text-muted">Unit: {{ item.unit_price }}</small>
|
||||
</div>
|
||||
<div class="fw-bold text-primary mb-3 fs-5">{{ item.total_price }}</div>
|
||||
<button class="btn btn-sm btn-outline-danger" data-product-id="{{ item.product_id }}" data-action="remove">
|
||||
<i class="bi bi-trash me-1"></i>Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cart Summary -->
|
||||
<div class="col-lg-4">
|
||||
<div class="cart-summary p-4">
|
||||
<h5 class="mb-3">
|
||||
<i class="bi bi-receipt me-2 text-primary"></i>Order Summary
|
||||
</h5>
|
||||
|
||||
<!-- Currency Selector -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted fw-bold">
|
||||
<i class="bi bi-currency-exchange me-1"></i>Display Currency
|
||||
</label>
|
||||
<select class="form-select form-select-sm" id="currencySelector">
|
||||
{% for currency in currencies %}
|
||||
<option value="{{ currency.code }}" {% if currency.code == user_currency %}selected{% endif %}>
|
||||
{{ currency.symbol }} {{ currency.name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<!-- Price Breakdown -->
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span><i class="bi bi-bag me-1"></i>Subtotal ({{ cart.item_count }} items)</span>
|
||||
<span class="fw-bold">{{ cart.subtotal }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted"><i class="bi bi-calculator me-1"></i>Platform fees</span>
|
||||
<span class="text-muted">Calculated at checkout</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted"><i class="bi bi-truck me-1"></i>Deployment</span>
|
||||
<span class="text-success fw-bold">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between mb-4">
|
||||
<span class="fw-bold fs-5">Total</span>
|
||||
<span class="fw-bold text-primary fs-4">{{ cart.total }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Guest User Notice -->
|
||||
{% if not user_json %}
|
||||
<div class="alert alert-info mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<div>
|
||||
<strong>Almost ready to checkout!</strong><br>
|
||||
<small>You'll need to log in or create an account to complete your purchase. Don't worry - your cart items will be saved!</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Checkout Button -->
|
||||
<div class="d-grid mb-3">
|
||||
{% if user_json %}
|
||||
<a href="/checkout" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-credit-card me-2"></i>Proceed to Checkout
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="btn btn-primary btn-lg" id="checkoutBtn">
|
||||
<i class="bi bi-credit-card me-2"></i>Proceed to Checkout
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Security Notice -->
|
||||
<div class="security-notice p-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-shield-check text-success me-2 fs-5"></i>
|
||||
<div>
|
||||
<small class="fw-bold">Secure Checkout</small>
|
||||
<div class="small text-muted">256-bit SSL encryption</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recommended Products -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-stars me-2"></i>Recommended for you
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% for product_data in recommended_products %}
|
||||
<div class="d-flex align-items-center p-3 border rounded hover-shadow mb-3" style="transition: all 0.2s ease;">
|
||||
<i class="bi bi-cpu text-primary me-3 fs-4"></i>
|
||||
<div class="flex-grow-1">
|
||||
<div class="fw-bold">{{ product_data.product.name }}</div>
|
||||
<small class="text-muted">{{ product_data.product.description }}</small>
|
||||
<div class="text-primary fw-bold mt-1">{{ product_data.formatted_price }}</div>
|
||||
</div>
|
||||
<button class="btn btn-sm btn-primary add-recommended-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-product-price="{{ product_data.price.display_amount }}"
|
||||
data-product-category="{{ product_data.product.category_id }}">
|
||||
<i class="bi bi-plus me-1"></i>Add
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<div class="text-center mt-3">
|
||||
<a href="/marketplace" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-shop me-1"></i>Browse All Products
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Clear Cart Confirmation Modal -->
|
||||
<div class="modal fade" id="clearCartModal" tabindex="-1" aria-labelledby="clearCartModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title" id="clearCartModalLabel">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>Clear Entire Cart
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-cart-x text-danger me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<p class="mb-1 fw-bold">Are you sure you want to clear your entire cart?</p>
|
||||
<p class="mb-0 text-muted small">This action will remove all items from your cart and cannot be undone.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-warning d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<small>All {{ cart.item_count }} items will be permanently removed from your cart.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x-circle me-1"></i>Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmClearCartBtn">
|
||||
<i class="bi bi-trash me-1"></i>Clear Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Remove Item Confirmation Modal -->
|
||||
<div class="modal fade" id="removeItemModal" tabindex="-1" aria-labelledby="removeItemModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-warning text-dark">
|
||||
<h5 class="modal-title" id="removeItemModalLabel">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>Remove Item
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<i class="bi bi-trash text-warning me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<p class="mb-1 fw-bold">Remove this item from your cart?</p>
|
||||
<p class="mb-0 text-muted small">This action cannot be undone.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info d-flex align-items-center">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<small>You can always add this item back later from the marketplace.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x-circle me-1"></i>Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-warning" id="confirmRemoveItemBtn">
|
||||
<i class="bi bi-trash me-1"></i>Remove Item
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div id="loadingOverlay" class="position-fixed top-0 start-0 w-100 h-100 d-none" style="background: rgba(0,0,0,0.5); z-index: 9999;">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<div class="spinner-border text-light" role="status" style="width: 3rem; height: 3rem;">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script type="application/json" id="cart-hydration">
|
||||
{
|
||||
"item_count": {{ cart.item_count }},
|
||||
"redirect_login_url": "/login?checkout=true",
|
||||
"redirect_register_url": "/register?checkout=true",
|
||||
"redirect_after_auth": "/cart"
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/cart.js"></script>
|
||||
|
||||
<!-- Guest Checkout Modal -->
|
||||
<div class="modal fade" id="guestCheckoutModal" tabindex="-1" aria-labelledby="guestCheckoutModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-primary text-white">
|
||||
<h5 class="modal-title" id="guestCheckoutModalLabel">
|
||||
<i class="bi bi-person-check me-2"></i>Complete Your Purchase
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="text-center mb-4">
|
||||
<i class="bi bi-cart-check text-primary" style="font-size: 3rem;"></i>
|
||||
<h4 class="mt-3 mb-2">Almost there!</h4>
|
||||
<p class="text-muted">You're just one step away from completing your purchase.</p>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info d-flex align-items-center mb-4">
|
||||
<i class="bi bi-shield-check me-2"></i>
|
||||
<div>
|
||||
<strong>Your cart is safe!</strong><br>
|
||||
<small>All items in your cart will be automatically saved when you log in or create an account.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-12">
|
||||
<h6 class="mb-3">Choose an option to continue:</h6>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 border-primary">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-person-fill text-primary mb-2" style="font-size: 2rem;"></i>
|
||||
<h6>Already have an account?</h6>
|
||||
<p class="text-muted small mb-3">Sign in to access your saved information and complete checkout quickly.</p>
|
||||
<button type="button" class="btn btn-primary w-100" id="guestLoginBtn">
|
||||
<i class="bi bi-box-arrow-in-right me-2"></i>Log In
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 border-success">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-person-plus-fill text-success mb-2" style="font-size: 2rem;"></i>
|
||||
<h6>New to ThreeFold?</h6>
|
||||
<p class="text-muted small mb-3">Create a free account to manage your orders and access exclusive features.</p>
|
||||
<button type="button" class="btn btn-success w-100" id="guestRegisterBtn">
|
||||
<i class="bi bi-person-plus me-2"></i>Create Account
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 p-3 bg-light rounded">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-auto">
|
||||
<i class="bi bi-lightning-charge text-warning" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h6 class="mb-1">Quick & Secure</h6>
|
||||
<small class="text-muted">Registration takes less than 30 seconds. Your payment information is protected with enterprise-grade security.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-arrow-left me-2"></i>Continue Shopping
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
342
src/views/marketplace/checkout.html
Normal file
342
src/views/marketplace/checkout.html
Normal file
@@ -0,0 +1,342 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Checkout - Project Mycelium</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.checkout-step {
|
||||
position: relative;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.checkout-step.active {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
border: 2px solid #2196f3;
|
||||
}
|
||||
|
||||
.checkout-step.completed {
|
||||
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
|
||||
border: 2px solid #4caf50;
|
||||
}
|
||||
|
||||
.step-number {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.step-number.active {
|
||||
background: #2196f3;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.step-number.completed {
|
||||
background: #4caf50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.step-number.pending {
|
||||
background: #e0e0e0;
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.payment-method {
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.payment-method:hover {
|
||||
border-color: #2196f3;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.payment-method.selected {
|
||||
border-color: #2196f3;
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
}
|
||||
|
||||
.order-summary {
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.security-badge {
|
||||
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
|
||||
border: 1px solid #4caf50;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #2196f3;
|
||||
box-shadow: 0 0 0 0.2rem rgba(33, 150, 243, 0.25);
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>Project Mycelium</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/marketplace">
|
||||
<i class="bi bi-shop me-1"></i>Marketplace
|
||||
</a>
|
||||
<a class="nav-link" href="/cart">
|
||||
<i class="bi bi-cart3 me-1"></i>Cart
|
||||
</a>
|
||||
<a class="nav-link active" href="/checkout">
|
||||
<i class="bi bi-credit-card me-1"></i>Checkout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-4 border-bottom">
|
||||
<h1 class="h2 mb-0">
|
||||
<i class="bi bi-credit-card me-2 text-primary"></i>Secure Checkout
|
||||
</h1>
|
||||
<div class="btn-toolbar">
|
||||
<a href="/cart" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1"></i>Back to Cart
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Checkout Steps -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between">
|
||||
<div class="checkout-step active flex-fill me-2">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="step-number active">1</div>
|
||||
<div>
|
||||
<div class="fw-bold">Review Order</div>
|
||||
<small class="text-muted">Verify your items</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="checkout-step pending flex-fill me-2">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="step-number pending">2</div>
|
||||
<div>
|
||||
<div class="fw-bold">Payment</div>
|
||||
<small class="text-muted">Choose payment method</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="checkout-step pending flex-fill">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="step-number pending">3</div>
|
||||
<div>
|
||||
<div class="fw-bold">Confirmation</div>
|
||||
<small class="text-muted">Order complete</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Checkout Form -->
|
||||
<div class="col-lg-8">
|
||||
<!-- Step 1: Order Review -->
|
||||
<div id="step1" class="checkout-section">
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-bag-check me-2"></i>Order Review
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if cart_details and cart_details.items %}
|
||||
{% for item in cart_details.items %}
|
||||
<div class="d-flex align-items-center p-3 border-bottom">
|
||||
<div class="me-3">
|
||||
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 50px; height: 50px;">
|
||||
{% if item.product.category_id == "compute" %}
|
||||
<i class="bi bi-cpu text-primary"></i>
|
||||
{% elif item.product.category_id == "hardware" %}
|
||||
<i class="bi bi-hdd-rack text-success"></i>
|
||||
{% elif item.product.category_id == "gateways" %}
|
||||
<i class="bi bi-globe text-info"></i>
|
||||
{% elif item.product.category_id == "applications" %}
|
||||
<i class="bi bi-app text-warning"></i>
|
||||
{% elif item.product.category_id == "services" %}
|
||||
<i class="bi bi-person-workspace text-secondary"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-box text-muted"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-1">{{ item.product.name }}</h6>
|
||||
<small class="text-muted">{{ item.product.provider_name }}</small>
|
||||
<div class="mt-1">
|
||||
<span class="badge bg-light text-dark">Qty: {{ item.cart_item.quantity }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="fw-bold text-primary">{{ item.unit_price.formatted_display }}</div>
|
||||
<small class="text-muted">per unit</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="text-center py-4">
|
||||
<i class="bi bi-cart-x fs-1 text-muted mb-3"></i>
|
||||
<h5 class="text-muted">No items in cart</h5>
|
||||
<a href="/marketplace" class="btn btn-primary">Browse Marketplace</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button class="btn btn-primary btn-lg" id="complete-order-btn">
|
||||
Complete Order <i class="bi bi-lock ms-1"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Summary -->
|
||||
<div class="col-lg-4">
|
||||
<div class="order-summary p-4">
|
||||
<h5 class="mb-3">
|
||||
<i class="bi bi-receipt me-2 text-primary"></i>Order Summary
|
||||
</h5>
|
||||
|
||||
{% if cart_details %}
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal ({{ cart_details.item_count }} items)</span>
|
||||
<span class="fw-bold" id="subtotal-display">{{ cart_details.subtotal }} {{ cart_details.currency }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Platform fee</span>
|
||||
<span class="text-muted">Free</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Deployment</span>
|
||||
<span class="text-success fw-bold">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between mb-4">
|
||||
<span class="fw-bold fs-5">Total</span>
|
||||
<span class="fw-bold text-primary fs-4" id="total-display">{{ cart_details.total }} {{ cart_details.currency }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Security Badges -->
|
||||
<div class="security-badge p-3 mb-3">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bi bi-shield-check text-success me-2 fs-5"></i>
|
||||
<div>
|
||||
<div class="fw-bold small">Secure Checkout</div>
|
||||
<div class="small text-muted">256-bit SSL encryption</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-lock text-success me-2 fs-5"></i>
|
||||
<div>
|
||||
<div class="fw-bold small">Privacy Protected</div>
|
||||
<div class="small text-muted">Your data is safe with us</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Support -->
|
||||
<div class="text-center">
|
||||
<small class="text-muted">
|
||||
Need help? <a href="https://threefoldfaq.crisp.help/en/" class="text-decoration-none" target="_blank">Contact Support</a>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Overlay -->
|
||||
<div id="loadingOverlay" class="position-fixed top-0 start-0 w-100 h-100 d-none" style="background: rgba(0,0,0,0.5); z-index: 9999;">
|
||||
<div class="d-flex justify-content-center align-items-center h-100">
|
||||
<div class="spinner-border text-light" role="status" style="width: 3rem; height: 3rem;">
|
||||
<span class="visually-hidden">Processing...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Modal + Errors utilities (must load before checkout.js) -->
|
||||
<script src="/static/js/modal-system.js"></script>
|
||||
<script src="/static/js/utils/errors.js"></script>
|
||||
|
||||
<!-- JSON hydration for checkout (CSP-safe) -->
|
||||
<script type="application/json" id="checkout-hydration">
|
||||
{
|
||||
"user_currency": {{ user_currency | default(value='USD') | json_encode() | safe }},
|
||||
"cart_details": {% if cart_details is defined %}{{ cart_details | json_encode() | safe }}{% else %}null{% endif %}
|
||||
}
|
||||
</script>
|
||||
<!-- External JS (CSP-compliant) -->
|
||||
<script src="/static/js/base.js"></script>
|
||||
<script src="/static/js/checkout.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
445
src/views/marketplace/compute_resources.html
Normal file
445
src/views/marketplace/compute_resources.html
Normal file
@@ -0,0 +1,445 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - Compute Resources{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<h1>Compute Resources (Slices)</h1>
|
||||
<p class="lead">Find and acquire the compute resources you need for your workloads.</p>
|
||||
|
||||
<!-- Enhanced Filter Section -->
|
||||
<div class="filter-section p-4 mb-4">
|
||||
<h5 class="mb-3">Filter Resources</h5>
|
||||
<form id="filterForm" method="GET">
|
||||
<div class="enhanced-filters">
|
||||
<div>
|
||||
<label class="form-label">Location</label>
|
||||
<select name="location" class="form-select">
|
||||
<option value="">All Locations</option>
|
||||
<option value="Belgium">Belgium</option>
|
||||
<option value="Austria">Austria</option>
|
||||
<option value="Switzerland">Switzerland</option>
|
||||
<option value="Netherlands">Netherlands</option>
|
||||
<option value="Germany">Germany</option>
|
||||
<option value="France">France</option>
|
||||
<option value="UK">UK</option>
|
||||
<option value="Canada">Canada</option>
|
||||
<option value="USA">USA</option>
|
||||
<option value="Japan">Japan</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Min vCores</label>
|
||||
<select name="min_cores" class="form-select">
|
||||
<option value="">Any</option>
|
||||
<option value="1">1 Core+</option>
|
||||
<option value="2">2 Cores+</option>
|
||||
<option value="4">4 Cores+</option>
|
||||
<option value="8">8 Cores+</option>
|
||||
<option value="16">16 Cores+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Min RAM (GB)</label>
|
||||
<select name="min_memory" class="form-select">
|
||||
<option value="">Any</option>
|
||||
<option value="4">4 GB+</option>
|
||||
<option value="8">8 GB+</option>
|
||||
<option value="16">16 GB+</option>
|
||||
<option value="32">32 GB+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Min Storage (GB)</label>
|
||||
<select name="min_storage" class="form-select">
|
||||
<option value="">Any</option>
|
||||
<option value="200">200 GB+</option>
|
||||
<option value="500">500 GB+</option>
|
||||
<option value="1000">1 TB+</option>
|
||||
<option value="2000">2 TB+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Min Uptime (%)</label>
|
||||
<select name="min_uptime" class="form-select">
|
||||
<option value="">Any</option>
|
||||
<option value="95">95%+</option>
|
||||
<option value="98">98%+</option>
|
||||
<option value="99">99%+</option>
|
||||
<option value="99.9">99.9%+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Min Bandwidth (Mbps)</label>
|
||||
<select name="min_bandwidth" class="form-select">
|
||||
<option value="">Any</option>
|
||||
<option value="100">100 Mbps+</option>
|
||||
<option value="500">500 Mbps+</option>
|
||||
<option value="1000">1 Gbps+</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Price Range ($)</label>
|
||||
<div class="d-flex gap-2">
|
||||
<input type="number" name="min_price" class="form-control" placeholder="Min" style="width: 80px;">
|
||||
<input type="number" name="max_price" class="form-control" placeholder="Max" style="width: 80px;">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="btn btn-primary">Apply Filters</button>
|
||||
<a href="/marketplace/compute" class="btn btn-outline-secondary ms-2">Clear</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Table Section -->
|
||||
{% if compute_products and compute_products | length > 0 %}
|
||||
<div class="compute-table">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 15%;">Type</th>
|
||||
<th style="width: 12%;">Provider</th>
|
||||
<th style="width: 10%;">Location</th>
|
||||
<th style="width: 8%;">vCores</th>
|
||||
<th style="width: 8%;">RAM</th>
|
||||
<th style="width: 10%;">Storage (SSD)</th>
|
||||
<th style="width: 10%;">Uptime SLA</th>
|
||||
<th style="width: 10%;">Bandwidth SLA</th>
|
||||
<th style="width: 8%;">Price/Hour</th>
|
||||
<th style="width: 9%;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for product_data in compute_products %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="slice-name">{{ product_data.product.name }}</div>
|
||||
<div class="slice-info">
|
||||
<small class="text-muted d-block">
|
||||
{% if product_data.product.attributes.cpu_cores %}
|
||||
{{ product_data.product.attributes.cpu_cores.value }}x Base Unit
|
||||
{% else %}
|
||||
Compute slice
|
||||
{% endif %}
|
||||
</small>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="provider-name">
|
||||
{% if product_data.product.attributes.farmer_email %}
|
||||
{{ product_data.product.attributes.farmer_email.value | truncate(length=15) }}
|
||||
{% else %}
|
||||
{% if product_data.product.provider %}{{ product_data.product.provider }}{% else %}Unknown{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{% if product_data.product.metadata.location %}
|
||||
<span class="location-badge node-location"
|
||||
data-location="{{ product_data.product.metadata.location }}">
|
||||
{{ product_data.product.metadata.location }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if product_data.product.attributes.cpu_cores %}
|
||||
<span class="spec-value">{{ product_data.product.attributes.cpu_cores.value }}</span>
|
||||
<span class="spec-unit">cores</span>
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if product_data.product.attributes.memory_gb %}
|
||||
<span class="spec-value">{{ product_data.product.attributes.memory_gb.value }}</span>
|
||||
<span class="spec-unit">GB</span>
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if product_data.product.attributes.storage_gb %}
|
||||
<span class="spec-value">{{ product_data.product.attributes.storage_gb.value }}</span>
|
||||
<span class="spec-unit">GB</span>
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if product_data.product.attributes.uptime_percentage %}
|
||||
<div class="sla-indicator sla-good">
|
||||
<i class="bi bi-check-circle-fill"></i>
|
||||
<span>{{ product_data.product.attributes.uptime_percentage.value | format_decimal(precision=1) }}%</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if product_data.product.attributes.bandwidth_mbps %}
|
||||
<div class="sla-indicator sla-good">
|
||||
<i class="bi bi-speedometer2"></i>
|
||||
<span>{{ product_data.product.attributes.bandwidth_mbps.value }} Mbps</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="sla-indicator sla-good">
|
||||
<i class="bi bi-speedometer2"></i>
|
||||
<span>1000 Mbps</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="price-display">{{ product_data.formatted_price }}</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-buttons">
|
||||
<button class="btn btn-success btn-sm-custom buy-now-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}"
|
||||
data-category="compute">
|
||||
<i class="bi bi-lightning-charge"></i> Buy Now
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm-custom add-to-cart-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus"></i> Add to Cart
|
||||
</button>
|
||||
<a class="btn btn-outline-secondary btn-sm-custom" href="/products/{{ product_data.product.id }}">
|
||||
<i class="bi bi-eye"></i> View
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-inbox display-1 text-muted"></i>
|
||||
<h4 class="mt-3">No Compute Resources Available</h4>
|
||||
<p class="text-muted">Check back later for new compute resources.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if pagination and pagination.total_pages > 1 %}
|
||||
<nav aria-label="Resource pages" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<!-- Previous Page -->
|
||||
<li class="page-item {% if not pagination.has_previous %}disabled{% endif %}">
|
||||
{% if pagination.has_previous %}
|
||||
<a class="page-link" href="?page={{ pagination.previous_page }}">Previous</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Previous</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 1 -->
|
||||
<li class="page-item {% if pagination.current_page == 0 %}active{% endif %}">
|
||||
{% if pagination.current_page == 0 %}
|
||||
<span class="page-link">1</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=0">1</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 2 (if exists) -->
|
||||
{% if pagination.total_pages > 1 %}
|
||||
<li class="page-item {% if pagination.current_page == 1 %}active{% endif %}">
|
||||
{% if pagination.current_page == 1 %}
|
||||
<span class="page-link">2</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=1">2</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 3 (if exists) -->
|
||||
{% if pagination.total_pages > 2 %}
|
||||
<li class="page-item {% if pagination.current_page == 2 %}active{% endif %}">
|
||||
{% if pagination.current_page == 2 %}
|
||||
<span class="page-link">3</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=2">3</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 4 (if exists) -->
|
||||
{% if pagination.total_pages > 3 %}
|
||||
<li class="page-item {% if pagination.current_page == 3 %}active{% endif %}">
|
||||
{% if pagination.current_page == 3 %}
|
||||
<span class="page-link">4</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=3">4</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 5 (if exists) -->
|
||||
{% if pagination.total_pages > 4 %}
|
||||
<li class="page-item {% if pagination.current_page == 4 %}active{% endif %}">
|
||||
{% if pagination.current_page == 4 %}
|
||||
<span class="page-link">5</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=4">5</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Next Page -->
|
||||
<li class="page-item {% if not pagination.has_next %}disabled{% endif %}">
|
||||
{% if pagination.has_next %}
|
||||
<a class="page-link" href="?page={{ pagination.next_page }}">Next</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Next</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Results Info -->
|
||||
<div class="text-center text-muted mt-2">
|
||||
Showing page {{ pagination.current_page + 1 }} of {{ pagination.total_pages }}
|
||||
({{ pagination.total_count }} total compute resources)
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.compute-table {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.compute-table th {
|
||||
background-color: #f8f9fa;
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
font-weight: 600;
|
||||
color: #495057;
|
||||
padding: 12px 8px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.compute-table td {
|
||||
padding: 12px 8px;
|
||||
vertical-align: middle;
|
||||
border-bottom: 1px solid #f1f3f4;
|
||||
}
|
||||
|
||||
.compute-table tbody tr:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.provider-name {
|
||||
font-weight: 600;
|
||||
color: #0d6efd;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.slice-info {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.slice-name {
|
||||
font-weight: 500;
|
||||
color: #212529;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.spec-value {
|
||||
font-weight: 500;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.spec-unit {
|
||||
color: #6c757d;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.location-badge {
|
||||
background-color: #e3f2fd;
|
||||
color: #1976d2;
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.sla-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.sla-good { color: #28a745; }
|
||||
.sla-medium { color: #ffc107; }
|
||||
.sla-low { color: #dc3545; }
|
||||
|
||||
.price-display {
|
||||
font-weight: 600;
|
||||
color: #0d6efd;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.btn-sm-custom {
|
||||
padding: 4px 8px;
|
||||
font-size: 0.8rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.compute-table {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.compute-table th,
|
||||
.compute-table td {
|
||||
padding: 8px 4px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-section {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.enhanced-filters {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
align-items: end;
|
||||
}
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script type="application/json" id="compute-hydration">{}</script>
|
||||
<script src="/static/js/marketplace-compute.js"></script>
|
||||
{% endblock %}
|
||||
376
src/views/marketplace/dashboard.html
Normal file
376
src/views/marketplace/dashboard.html
Normal file
@@ -0,0 +1,376 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - Overview{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<h1>Project Mycelium Overview</h1>
|
||||
<p class="lead">Explore the decentralized ecosystem of resources, applications, and services.</p>
|
||||
|
||||
<!-- Overview Stats -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-3">
|
||||
<div class="card text-white bg-primary mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Compute Resources</h5>
|
||||
<p class="card-text">250+ available slices</p>
|
||||
<a href="/marketplace/compute" class="text-white">Browse Resources →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card text-white bg-success mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">3Nodes</h5>
|
||||
<p class="card-text">120+ certified nodes</p>
|
||||
<a href="/marketplace/3nodes" class="text-white">Browse 3Nodes →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card text-white bg-info mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Gateways</h5>
|
||||
<p class="card-text">45+ active gateways</p>
|
||||
<a href="/marketplace/gateways" class="text-white">Browse Gateways →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card text-white bg-warning mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Applications</h5>
|
||||
<p class="card-text">80+ self-healing apps</p>
|
||||
<a href="/marketplace/applications" class="text-white">Browse Applications →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Featured Items -->
|
||||
<h2 class="mt-5 mb-4">Featured Items</h2>
|
||||
<div class="row">
|
||||
{% if featured_products is defined and featured_products | length > 0 %}
|
||||
{% for item in featured_products %}
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="marketplace-item">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
{% set cat = 'other' %}
|
||||
{% if item.product is defined and item.product.category_id is defined %}
|
||||
{% set cat = item.product.category_id %}
|
||||
{% endif %}
|
||||
<span class="badge bg-{% if cat == 'compute' %}primary{% elif cat == 'hardware' %}success{% elif cat == 'gateway' %}info{% elif cat == 'application' %}warning{% else %}secondary{% endif %} badge-category">
|
||||
{{ cat }}
|
||||
</span>
|
||||
{% if item.product is defined and item.product.metadata is defined and (item.product.metadata.featured | default(value=false)) %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% set prod_name = 'Unnamed' %}
|
||||
{% set prod_desc = '' %}
|
||||
{% set provider_name = '' %}
|
||||
{% set prod_id = '' %}
|
||||
{% set category_id = '' %}
|
||||
{% set base_price = 0 %}
|
||||
{% set provider_id = '' %}
|
||||
{% if item.product is defined %}
|
||||
{% if item.product.name is defined %}{% set prod_name = item.product.name %}{% endif %}
|
||||
{% if item.product.description is defined %}{% set prod_desc = item.product.description %}{% endif %}
|
||||
{% if item.product.provider_name is defined %}{% set provider_name = item.product.provider_name %}{% endif %}
|
||||
{% if item.product.id is defined %}{% set prod_id = item.product.id %}{% endif %}
|
||||
{% if item.product.category_id is defined %}{% set category_id = item.product.category_id %}{% endif %}
|
||||
{% if item.product.base_price is defined %}{% set base_price = item.product.base_price %}{% endif %}
|
||||
{% if item.product.provider_id is defined %}{% set provider_id = item.product.provider_id %}{% endif %}
|
||||
{% endif %}
|
||||
<h4>{{ prod_name }}</h4>
|
||||
<p>{{ prod_desc }}</p>
|
||||
|
||||
<!-- Product Specifications -->
|
||||
{% if item.product is defined and item.product.attributes is defined and item.product.attributes | length > 0 %}
|
||||
<div class="row mb-3">
|
||||
{% for attr_name, attr_value in item.product.attributes %}
|
||||
{% if attr_name == "cpu_cores" %}
|
||||
<div class="col-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-cpu me-1"></i>
|
||||
<small>{{ attr_value.value | default(value='') }} Cores</small>
|
||||
</div>
|
||||
</div>
|
||||
{% elif attr_name == "memory_gb" %}
|
||||
<div class="col-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-memory me-1"></i>
|
||||
<small>{{ attr_value.value | default(value='') }} GB RAM</small>
|
||||
</div>
|
||||
</div>
|
||||
{% elif attr_name == "storage_gb" %}
|
||||
<div class="col-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-hdd me-1"></i>
|
||||
<small>{{ attr_value.value | default(value='') }} GB Storage</small>
|
||||
</div>
|
||||
</div>
|
||||
{% elif attr_name == "location" %}
|
||||
<div class="col-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-geo-alt me-1"></i>
|
||||
<small>{{ attr_value.value | default(value='') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span class="text-primary fw-bold">{{ item.formatted_price | default(value="") }}</span>
|
||||
<br><small class="text-muted">by {{ provider_name }}</small>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-success buy-now-btn"
|
||||
data-product-id="{{ prod_id }}"
|
||||
data-product-name="{{ prod_name }}"
|
||||
data-category="{{ category_id }}"
|
||||
data-unit-price="{{ base_price }}"
|
||||
data-provider-id="{{ provider_id }}"
|
||||
data-provider-name="{{ provider_name }}"
|
||||
title="Buy instantly with your wallet balance">
|
||||
<i class="bi bi-lightning-fill me-1"></i>Buy Now
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary add-to-cart-btn"
|
||||
data-product-id="{{ prod_id }}"
|
||||
data-product-name="{{ prod_name }}"
|
||||
data-product-price="{{ item.formatted_price | default(value='') }}">
|
||||
<i class="bi bi-cart-plus me-1"></i>Add to Cart
|
||||
</button>
|
||||
<a href="/products/{{ prod_id }}" class="btn btn-sm btn-outline-primary">
|
||||
View Details
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
No featured products available at the moment.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Popular Applications -->
|
||||
<h2 class="mt-5 mb-4">Popular Applications</h2>
|
||||
<div class="row">
|
||||
{% if popular_applications is defined and popular_applications | length > 0 %}
|
||||
{% for item in popular_applications %}
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="marketplace-item">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<span class="badge bg-warning badge-category">Application</span>
|
||||
{% if item.product is defined and item.product.metadata is defined and (item.product.metadata.featured | default(value=false)) %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% set prod_name = 'Unnamed' %}
|
||||
{% set prod_desc = '' %}
|
||||
{% set provider_name = '' %}
|
||||
{% set prod_id = '' %}
|
||||
{% set category_id = '' %}
|
||||
{% set base_price = 0 %}
|
||||
{% set provider_id = '' %}
|
||||
{% set unit_price = 0 %}
|
||||
{% set currency = '' %}
|
||||
{% if item.product is defined %}
|
||||
{% if item.product.name is defined %}{% set prod_name = item.product.name %}{% endif %}
|
||||
{% if item.product.description is defined %}{% set prod_desc = item.product.description %}{% endif %}
|
||||
{% if item.product.provider_name is defined %}{% set provider_name = item.product.provider_name %}{% endif %}
|
||||
{% if item.product.id is defined %}{% set prod_id = item.product.id %}{% endif %}
|
||||
{% if item.product.category_id is defined %}{% set category_id = item.product.category_id %}{% endif %}
|
||||
{% if item.product.base_price is defined %}{% set base_price = item.product.base_price %}{% endif %}
|
||||
{% if item.product.provider_id is defined %}{% set provider_id = item.product.provider_id %}{% endif %}
|
||||
{% endif %}
|
||||
{% if item.price is defined %}
|
||||
{% if item.price.display_amount is defined %}{% set unit_price = item.price.display_amount %}{% endif %}
|
||||
{% if item.price.display_currency is defined %}{% set currency = item.price.display_currency %}{% endif %}
|
||||
{% endif %}
|
||||
<h4>{{ prod_name }}</h4>
|
||||
<p>{{ prod_desc | truncate(length=100) }}</p>
|
||||
|
||||
<!-- Application Specifications -->
|
||||
{% if item.product is defined and item.product.attributes is defined and item.product.attributes | length > 0 %}
|
||||
<div class="row mb-3">
|
||||
{% if item.product.attributes is defined and item.product.attributes.app_type is defined %}
|
||||
<div class="col-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-app me-1"></i>
|
||||
<small>{{ item.product.attributes.app_type.value | default(value='') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if item.product.attributes is defined and item.product.attributes.deployment_type is defined %}
|
||||
<div class="col-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-box me-1"></i>
|
||||
<small>{{ item.product.attributes.deployment_type.value | default(value='') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span class="text-primary fw-bold">{{ item.formatted_price | default(value="") }}</span>
|
||||
<br><small class="text-muted">by {{ provider_name }}</small>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-success buy-now-btn"
|
||||
data-product-id="{{ prod_id }}"
|
||||
data-product-name="{{ prod_name }}"
|
||||
data-unit-price="{{ unit_price }}"
|
||||
data-currency="{{ currency }}">
|
||||
<i class="bi bi-lightning-fill me-1"></i>Buy Now
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary add-to-cart-btn"
|
||||
data-product-id="{{ prod_id }}"
|
||||
data-product-name="{{ prod_name }}"
|
||||
data-category="{{ category_id }}"
|
||||
data-unit-price="{{ base_price }}"
|
||||
data-provider-id="{{ provider_id }}"
|
||||
data-provider-name="{{ provider_name }}"
|
||||
data-quantity="1"
|
||||
title="Buy instantly with your wallet balance">
|
||||
<i class="bi bi-cart-plus me-1"></i>Add to Cart
|
||||
</button>
|
||||
<a href="/products/{{ prod_id }}" class="btn btn-sm btn-outline-primary">
|
||||
View Details
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
No popular applications available at the moment.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Available Services -->
|
||||
<h2 class="mt-5 mb-4">Available Services</h2>
|
||||
<div class="row">
|
||||
{% if available_services is defined and available_services | length > 0 %}
|
||||
{% for item in available_services %}
|
||||
<div class="col-md-6 col-lg-4 mb-4">
|
||||
<div class="marketplace-item">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<span class="badge bg-secondary badge-category">Service</span>
|
||||
{% if item.product is defined and item.product.metadata is defined and (item.product.metadata.featured | default(value=false)) %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% set prod_name = 'Unnamed' %}
|
||||
{% set prod_desc = '' %}
|
||||
{% set provider_name = '' %}
|
||||
{% set prod_id = '' %}
|
||||
{% set category_id = '' %}
|
||||
{% set base_price = 0 %}
|
||||
{% set provider_id = '' %}
|
||||
{% set unit_price = 0 %}
|
||||
{% set currency = '' %}
|
||||
{% if item.product is defined %}
|
||||
{% if item.product.name is defined %}{% set prod_name = item.product.name %}{% endif %}
|
||||
{% if item.product.description is defined %}{% set prod_desc = item.product.description %}{% endif %}
|
||||
{% if item.product.provider_name is defined %}{% set provider_name = item.product.provider_name %}{% endif %}
|
||||
{% if item.product.id is defined %}{% set prod_id = item.product.id %}{% endif %}
|
||||
{% if item.product.category_id is defined %}{% set category_id = item.product.category_id %}{% endif %}
|
||||
{% if item.product.base_price is defined %}{% set base_price = item.product.base_price %}{% endif %}
|
||||
{% if item.product.provider_id is defined %}{% set provider_id = item.product.provider_id %}{% endif %}
|
||||
{% endif %}
|
||||
{% if item.price is defined %}
|
||||
{% if item.price.display_amount is defined %}{% set unit_price = item.price.display_amount %}{% endif %}
|
||||
{% if item.price.display_currency is defined %}{% set currency = item.price.display_currency %}{% endif %}
|
||||
{% endif %}
|
||||
<h4>{{ prod_name }}</h4>
|
||||
<p>{{ prod_desc | truncate(length=100) }}</p>
|
||||
|
||||
<!-- Service Specifications -->
|
||||
{% if item.product is defined and item.product.attributes is defined and item.product.attributes | length > 0 %}
|
||||
<div class="row mb-3">
|
||||
{% if item.product.attributes is defined and item.product.attributes.service_type is defined %}
|
||||
<div class="col-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-gear me-1"></i>
|
||||
<small>{{ item.product.attributes.service_type.value | default(value='') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if item.product.attributes is defined and item.product.attributes.expertise_level is defined %}
|
||||
<div class="col-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-star me-1"></i>
|
||||
<small>{{ item.product.attributes.expertise_level.value | default(value='') }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span class="text-primary fw-bold">{{ item.formatted_price | default(value="") }}</span>
|
||||
<br><small class="text-muted">by {{ provider_name }}</small>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-success buy-now-btn"
|
||||
data-product-id="{{ prod_id }}"
|
||||
data-product-name="{{ prod_name }}"
|
||||
data-unit-price="{{ unit_price }}"
|
||||
data-currency="{{ currency }}">
|
||||
<i class="bi bi-lightning-fill me-1"></i>Buy Now
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-primary add-to-cart-btn"
|
||||
data-product-id="{{ prod_id }}"
|
||||
data-product-name="{{ prod_name }}"
|
||||
data-category="{{ category_id }}"
|
||||
data-unit-price="{{ base_price }}"
|
||||
data-provider-id="{{ provider_id }}"
|
||||
data-provider-name="{{ provider_name }}"
|
||||
data-quantity="1"
|
||||
title="Buy instantly with your wallet balance">
|
||||
<i class="bi bi-cart-plus me-1"></i>Add to Cart
|
||||
</button>
|
||||
<a href="/products/{{ prod_id }}" class="btn btn-sm btn-outline-primary">
|
||||
View Details
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
No services available at the moment.
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="application/json" id="marketplace-dashboard-hydration">{}</script>
|
||||
<script src="/static/js/marketplace_dashboard.js"></script>
|
||||
{% endblock %}
|
||||
320
src/views/marketplace/gateways.html
Normal file
320
src/views/marketplace/gateways.html
Normal file
@@ -0,0 +1,320 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - Mycelium Gateways{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<h1>Mycelium Gateways</h1>
|
||||
<p class="lead">Connect to the internet securely through the Mycelium network.</p>
|
||||
|
||||
<!-- Filter and Search Section -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filter Gateways</h5>
|
||||
<form class="row g-3" id="filterForm" method="GET">
|
||||
<div class="col-md-3">
|
||||
<label for="locationFilter" class="form-label">Location</label>
|
||||
<select name="location" id="locationFilter" class="form-select">
|
||||
<option value="">All Locations</option>
|
||||
<option value="Belgium">Belgium</option>
|
||||
<option value="Austria">Austria</option>
|
||||
<option value="Switzerland">Switzerland</option>
|
||||
<option value="Netherlands">Netherlands</option>
|
||||
<option value="Germany">Germany</option>
|
||||
<option value="France">France</option>
|
||||
<option value="UK">UK</option>
|
||||
<option value="Canada">Canada</option>
|
||||
<option value="USA">USA</option>
|
||||
<option value="Japan">Japan</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="speedFilter" class="form-label">Minimum Speed</label>
|
||||
<select name="bandwidth_mbps" id="speedFilter" class="form-select">
|
||||
<option value="">Any</option>
|
||||
<option value="100">100+ Mbps</option>
|
||||
<option value="500">500+ Mbps</option>
|
||||
<option value="1000">1+ Gbps</option>
|
||||
<option value="2500">2.5+ Gbps</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="minPriceFilter" class="form-label">Min Price ($)</label>
|
||||
<input type="number" name="min_price" id="minPriceFilter" class="form-control"
|
||||
value="" placeholder="0" min="0" step="1">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="maxPriceFilter" class="form-label">Max Price ($)</label>
|
||||
<input type="number" name="max_price" id="maxPriceFilter" class="form-control"
|
||||
value="" placeholder="300" min="0" step="1">
|
||||
</div>
|
||||
<div class="col-md-6 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-primary me-2">Apply Filters</button>
|
||||
<a href="/marketplace/gateways" class="btn btn-outline-secondary">Clear</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Available Gateways Section -->
|
||||
<div class="row">
|
||||
{% if gateway_products and gateway_products | length > 0 %}
|
||||
{% for product_data in gateway_products %}
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="marketplace-item">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<h4 class="mb-0">
|
||||
<a href="/products/{{ product_data.product.id }}" class="text-decoration-none text-dark">
|
||||
{{ product_data.product.name }}
|
||||
</a>
|
||||
</h4>
|
||||
{% if product_data.product.metadata.featured %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% elif product_data.product.availability == "Available" %}
|
||||
<span class="badge bg-success">Available</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ product_data.product.availability }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Gateway Status -->
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<div class="gateway-status-indicator bg-success me-2" title="Online"></div>
|
||||
<span>Online -
|
||||
{% if product_data.product.attributes.uptime_sla %}
|
||||
{{ product_data.product.attributes.uptime_sla.value }}
|
||||
{% else %}
|
||||
99.9%
|
||||
{% endif %}
|
||||
uptime in last 30 days
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Product Specifications -->
|
||||
<div class="row mb-3">
|
||||
{% if product_data.product.attributes.bandwidth_mbps %}
|
||||
<div class="col-md-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-speedometer me-2"></i>
|
||||
<span>Speed: {{ product_data.product.attributes.bandwidth_mbps.value }} Mbps</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.uptime_sla %}
|
||||
<div class="col-md-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-shield-check me-2"></i>
|
||||
<span>SLA: {{ product_data.product.attributes.uptime_sla.value }} Uptime</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Additional Info -->
|
||||
<div class="row mb-3">
|
||||
{% if product_data.product.metadata.location %}
|
||||
<div class="col-md-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-geo-alt me-2"></i>
|
||||
<span>Location: {{ product_data.product.metadata.location }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-md-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-clock-history me-2"></i>
|
||||
<span>Provider: {{ product_data.product.provider_name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<p class="mb-4">{{ product_data.product.description | truncate(length=120) }}</p>
|
||||
|
||||
<!-- Features (if available in tags) -->
|
||||
{% if product_data.product.metadata.tags and product_data.product.metadata.tags | length > 0 %}
|
||||
<div class="mb-3">
|
||||
<h6>Features:</h6>
|
||||
<ul class="small">
|
||||
{% for tag in product_data.product.metadata.tags %}
|
||||
<li>{{ tag | title }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Price and Actions -->
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="price-container">
|
||||
<span class="text-muted">Price:</span>
|
||||
<span class="text-primary fw-bold">{{ product_data.formatted_price }}</span>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-success btn-sm buy-now-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}"
|
||||
data-category="gateways">
|
||||
<i class="bi bi-lightning-fill me-1"></i>Buy Now
|
||||
</button>
|
||||
<button class="btn btn-outline-primary btn-sm add-to-cart-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus me-1"></i>Add to Cart
|
||||
</button>
|
||||
<a href="/products/{{ product_data.product.id }}" class="btn btn-outline-secondary btn-sm">View Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-router display-1 text-muted"></i>
|
||||
<h4 class="mt-3">No Gateways Available</h4>
|
||||
<p class="text-muted">Check back later for new gateway services.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Gateway Configuration Guide -->
|
||||
<div class="card mt-5">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">How to Configure Your Gateway</h3>
|
||||
<p>Connecting your applications to a Mycelium Gateway is simple:</p>
|
||||
|
||||
<ol>
|
||||
<li>Choose a gateway from the options above</li>
|
||||
<li>Click the "Configure" button to start the setup process</li>
|
||||
<li>Register or select a <a href="/marketplace/names">Mycelium Name</a> for your gateway</li>
|
||||
<li>Configure domain routing and access controls</li>
|
||||
<li>Connect your application by updating the configuration with the provided Mycelium address</li>
|
||||
</ol>
|
||||
|
||||
<div class="alert alert-info mt-3">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
Need help setting up your gateway? <a href="/marketplace/services">Our technical experts</a> can assist with configuration and optimization.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if pagination and pagination.total_pages > 1 %}
|
||||
<nav aria-label="Gateway pages" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<!-- Previous Page -->
|
||||
<li class="page-item {% if not pagination.has_previous %}disabled{% endif %}">
|
||||
{% if pagination.has_previous %}
|
||||
<a class="page-link" href="?page={{ pagination.previous_page }}">Previous</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Previous</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 1 -->
|
||||
<li class="page-item {% if pagination.current_page == 0 %}active{% endif %}">
|
||||
{% if pagination.current_page == 0 %}
|
||||
<span class="page-link">1</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=0">1</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 2 (if exists) -->
|
||||
{% if pagination.total_pages > 1 %}
|
||||
<li class="page-item {% if pagination.current_page == 1 %}active{% endif %}">
|
||||
{% if pagination.current_page == 1 %}
|
||||
<span class="page-link">2</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=1">2</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 3 (if exists) -->
|
||||
{% if pagination.total_pages > 2 %}
|
||||
<li class="page-item {% if pagination.current_page == 2 %}active{% endif %}">
|
||||
{% if pagination.current_page == 2 %}
|
||||
<span class="page-link">3</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=2">3</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 4 (if exists) -->
|
||||
{% if pagination.total_pages > 3 %}
|
||||
<li class="page-item {% if pagination.current_page == 3 %}active{% endif %}">
|
||||
{% if pagination.current_page == 3 %}
|
||||
<span class="page-link">4</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=3">4</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 5 (if exists) -->
|
||||
{% if pagination.total_pages > 4 %}
|
||||
<li class="page-item {% if pagination.current_page == 4 %}active{% endif %}">
|
||||
{% if pagination.current_page == 4 %}
|
||||
<span class="page-link">5</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=4">5</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Next Page -->
|
||||
<li class="page-item {% if not pagination.has_next %}disabled{% endif %}">
|
||||
{% if pagination.has_next %}
|
||||
<a class="page-link" href="?page={{ pagination.next_page }}">Next</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Next</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Results Info -->
|
||||
<div class="text-center text-muted mt-2">
|
||||
Showing page {{ pagination.current_page + 1 }} of {{ pagination.total_pages }}
|
||||
({{ pagination.total_count }} total gateways)
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.gateway-status-indicator {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.gateway-status-indicator.bg-success {
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
.gateway-status-indicator.bg-warning {
|
||||
background-color: #ffc107;
|
||||
}
|
||||
|
||||
.gateway-status-indicator.bg-danger {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
|
||||
.spec-item {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.price-container {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="/static/js/marketplace-category.js"></script>
|
||||
{% endblock %}
|
||||
160
src/views/marketplace/layout.html
Normal file
160
src/views/marketplace/layout.html
Normal file
@@ -0,0 +1,160 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar Toggle Button (mobile only) -->
|
||||
<button class="btn sidebar-toggle d-md-none" id="sidebarToggleBtn" aria-label="Toggle sidebar navigation" aria-expanded="false" aria-controls="sidebar">
|
||||
<i class="bi bi-list"></i> Menu
|
||||
</button>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse" id="sidebar">
|
||||
<div class="position-sticky pt-3">
|
||||
<h5 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mb-1 text-muted">
|
||||
<span>Marketplace</span>
|
||||
</h5>
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'dashboard' %}active{% endif %}" href="/marketplace">
|
||||
<i class="bi bi-speedometer2 me-1"></i>
|
||||
Overview
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'statistics' %}active{% endif %}" href="/marketplace/statistics">
|
||||
<i class="bi bi-graph-up me-1"></i>
|
||||
Statistics
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'compute_resources' %}active{% endif %}" href="/marketplace/compute">
|
||||
<i class="bi bi-cpu me-1"></i>
|
||||
Compute Resources
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'three_nodes' %}active{% endif %}" href="/marketplace/3nodes">
|
||||
<i class="bi bi-hdd-rack me-1"></i>
|
||||
3Nodes
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'gateways' %}active{% endif %}" href="/marketplace/gateways">
|
||||
<i class="bi bi-globe me-1"></i>
|
||||
Mycelium Gateways
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'applications' %}active{% endif %}" href="/marketplace/applications">
|
||||
<i class="bi bi-app me-1"></i>
|
||||
Application Solutions
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {% if active_section == 'services' %}active{% endif %}" href="/marketplace/services">
|
||||
<i class="bi bi-person-workspace me-1"></i>
|
||||
Human Energy Services
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="col-md-9 ms-sm-auto col-lg-10 px-md-4 main-content-wrapper position-relative">
|
||||
<!-- Sidebar Backdrop (mobile only) - positioned here so it doesn't cover the sidebar -->
|
||||
<div class="sidebar-backdrop d-md-none" id="sidebarBackdrop"></div>
|
||||
{% block marketplace_content %}
|
||||
<!-- Content will be injected here by child templates -->
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
<!-- Add Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css">
|
||||
|
||||
<style>
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
top: 56px; /* Navbar height */
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
padding: 20px 0 0;
|
||||
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
|
||||
height: 100%; /* Full height */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* Footer should only appear on the right side */
|
||||
@media (min-width: 768px) {
|
||||
.footer {
|
||||
margin-left: 25%; /* Matches the width of col-md-3 */
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.footer {
|
||||
margin-left: 16.666667%; /* Matches the width of col-lg-2 */
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-heading {
|
||||
font-size: .75rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
color: #2470dc;
|
||||
}
|
||||
|
||||
.dashboard-section {
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
background-color: #f8f9fa;
|
||||
box-shadow: 0 .125rem .25rem rgba(0, 0, 0, .075);
|
||||
}
|
||||
|
||||
.marketplace-item {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 20px;
|
||||
background-color: white;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.marketplace-item:hover {
|
||||
box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
|
||||
.badge-category {
|
||||
font-size: 0.75rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* Adjust for fixed navbar */
|
||||
main.py-4 {
|
||||
padding-top: 4.5rem !important;
|
||||
}
|
||||
|
||||
/* Removed conflicting media query */
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="/static/js/marketplace_layout.js"></script>
|
||||
<!-- buy-now.js is now included in base.html -->
|
||||
{% endblock %}
|
||||
442
src/views/marketplace/order_confirmation.html
Normal file
442
src/views/marketplace/order_confirmation.html
Normal file
@@ -0,0 +1,442 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Order Confirmation - Project Mycelium</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
font-size: 4rem;
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.confirmation-card {
|
||||
background: linear-gradient(135deg, #e8f5e8 0%, #c8e6c9 100%);
|
||||
border: 2px solid #28a745;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.order-details {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.next-steps {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
border: 1px solid #2196f3;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-confirmed {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.order-tracking-timeline {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tracking-step {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 1rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tracking-step:not(:last-child)::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 32px;
|
||||
width: 2px;
|
||||
height: 20px;
|
||||
background: #dee2e6;
|
||||
}
|
||||
|
||||
.tracking-step.completed::after {
|
||||
background: #28a745;
|
||||
}
|
||||
|
||||
.tracking-step.active::after {
|
||||
background: #007bff;
|
||||
}
|
||||
|
||||
.step-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 12px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.step-content {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>Project Mycelium</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/marketplace">
|
||||
<i class="bi bi-shop me-1"></i>Marketplace
|
||||
</a>
|
||||
<a class="nav-link" href="/orders">
|
||||
<i class="bi bi-list-ul me-1"></i>My Orders
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
|
||||
|
||||
<!-- Success Message -->
|
||||
<div class="row justify-content-center mb-4">
|
||||
<div class="col-md-8">
|
||||
<div class="confirmation-card p-5 text-center">
|
||||
<i class="bi bi-check-circle success-icon mb-3"></i>
|
||||
<h1 class="h2 mb-3">Order Confirmed!</h1>
|
||||
<p class="lead mb-4">
|
||||
Thank you for your order. Your ThreeFold resources are being prepared for deployment.
|
||||
</p>
|
||||
{% if order %}
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-2">
|
||||
<strong>Order Number:</strong>
|
||||
</div>
|
||||
<div class="h5 text-primary">#{{ order.order_id }}</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-2">
|
||||
<strong>Confirmation Code:</strong>
|
||||
</div>
|
||||
<div class="h5 text-success">{{ order.confirmation_number }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Order Details -->
|
||||
<div class="col-lg-8">
|
||||
{% if order %}
|
||||
<div class="order-details p-4 mb-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h3><i class="bi bi-receipt me-2"></i>Order Details</h3>
|
||||
<span class="status-badge status-confirmed">
|
||||
<i class="bi bi-check-circle me-1"></i>{{ order.status }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Order Date:</strong>
|
||||
<div>{{ order.created_at }}</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Payment Method:</strong>
|
||||
<div>{{ order.payment_method }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Total Amount:</strong>
|
||||
<div class="h5 text-primary">{{ order.total }}</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Currency:</strong>
|
||||
<div>{{ order.currency }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="mb-3">Ordered Items</h5>
|
||||
{% for item in order.items %}
|
||||
<div class="d-flex align-items-center p-3 border rounded mb-3">
|
||||
<div class="me-3">
|
||||
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 50px; height: 50px;">
|
||||
{% if item.product_category == "compute" %}
|
||||
<i class="bi bi-cpu text-primary"></i>
|
||||
{% elif item.product_category == "hardware" %}
|
||||
<i class="bi bi-hdd-rack text-success"></i>
|
||||
{% elif item.product_category == "gateways" %}
|
||||
<i class="bi bi-globe text-info"></i>
|
||||
{% elif item.product_category == "applications" %}
|
||||
<i class="bi bi-app text-warning"></i>
|
||||
{% elif item.product_category == "services" %}
|
||||
<i class="bi bi-person-workspace text-secondary"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-box text-muted"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-1">{{ item.product_name }}</h6>
|
||||
<small class="text-muted">{{ item.provider_name }}</small>
|
||||
<div class="mt-1">
|
||||
<span class="badge bg-light text-dark">Qty: {{ item.quantity }}</span>
|
||||
<span class="badge bg-secondary ms-1">{{ item.product_category|title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="fw-bold">{{ item.unit_price }}</div>
|
||||
<small class="text-muted">per unit</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Next Steps -->
|
||||
<div class="next-steps p-4">
|
||||
<h5 class="mb-3">
|
||||
<i class="bi bi-arrow-right-circle me-2"></i>What's Next?
|
||||
</h5>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-1-circle fs-4 text-primary"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Processing</div>
|
||||
<small class="text-muted">Your order is being processed and resources are being allocated.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-2-circle fs-4 text-info"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Deployment</div>
|
||||
<small class="text-muted">Resources will be deployed to the ThreeFold Grid within 24 hours.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-3-circle fs-4 text-success"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Access</div>
|
||||
<small class="text-muted">You'll receive access credentials and connection details via email.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-4-circle fs-4 text-warning"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Support</div>
|
||||
<small class="text-muted">Our support team is available 24/7 to help with any questions.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-gear me-2"></i>Quick Actions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/orders" class="btn btn-primary">
|
||||
<i class="bi bi-list-ul me-2"></i>View All Orders
|
||||
</a>
|
||||
<a href="/marketplace" class="btn btn-outline-primary">
|
||||
<i class="bi bi-shop me-2"></i>Continue Shopping
|
||||
</a>
|
||||
<a href="/dashboard" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-speedometer2 me-2"></i>Go to Dashboard
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6 class="mb-3">Need Help?</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/docs" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-book me-1"></i>Docs
|
||||
</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-success" target="_blank">
|
||||
<i class="bi bi-chat-dots me-1"></i>Live Chat
|
||||
</a>
|
||||
<a href="mailto:support@threefold.io" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-envelope me-1"></i>Email Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Tracking -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-truck me-2"></i>Track Your Order
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="small text-muted mb-3">
|
||||
You can track the status of your order and deployment progress in real-time.
|
||||
</p>
|
||||
|
||||
<!-- Mock Order Tracking Timeline -->
|
||||
{% if order %}
|
||||
<div class="order-tracking-timeline mb-3">
|
||||
<div class="tracking-step completed">
|
||||
<div class="step-icon">
|
||||
<i class="bi bi-check-circle-fill text-success"></i>
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<div class="fw-bold">Order Confirmed</div>
|
||||
<small class="text-muted">{{ order.created_at }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tracking-step active">
|
||||
<div class="step-icon">
|
||||
<i class="bi bi-gear-fill text-primary"></i>
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<div class="fw-bold">Processing</div>
|
||||
<small class="text-muted">Resources being allocated</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tracking-step pending">
|
||||
<div class="step-icon">
|
||||
<i class="bi bi-cloud-arrow-up text-muted"></i>
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<div class="fw-bold">Deploying</div>
|
||||
<small class="text-muted">Setting up your resources</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tracking-step pending">
|
||||
<div class="step-icon">
|
||||
<i class="bi bi-check-all text-muted"></i>
|
||||
</div>
|
||||
<div class="step-content">
|
||||
<div class="fw-bold">Ready</div>
|
||||
<small class="text-muted">Resources available</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid">
|
||||
<a href="/orders/{{ order.order_id }}" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-eye me-1"></i>View Full Order Details
|
||||
</a>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="d-grid">
|
||||
<a href="/orders" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-list-ul me-1"></i>View Orders
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Email Confirmation -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-envelope-check fs-1 text-success mb-2"></i>
|
||||
<h6>Email Confirmation Sent</h6>
|
||||
<p class="small text-muted">
|
||||
A detailed confirmation has been sent to your email address with all order information and next steps.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
console.log('Order confirmation page loaded');
|
||||
|
||||
// Auto-scroll to top
|
||||
window.scrollTo(0, 0);
|
||||
|
||||
// Show success animation
|
||||
const successIcon = document.querySelector('.success-icon');
|
||||
if (successIcon) {
|
||||
successIcon.style.transform = 'scale(0)';
|
||||
setTimeout(() => {
|
||||
successIcon.style.transition = 'transform 0.5s ease-out';
|
||||
successIcon.style.transform = 'scale(1)';
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
311
src/views/marketplace/order_detail.html
Normal file
311
src/views/marketplace/order_detail.html
Normal file
@@ -0,0 +1,311 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Order Details - Project Mycelium</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.order-header {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
border: 2px solid #2196f3;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.order-details {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-confirmed {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
border: 1px solid #ffeaa7;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border: 1px solid #bee5eb;
|
||||
}
|
||||
|
||||
.status-failed {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>Project Mycelium</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/marketplace">
|
||||
<i class="bi bi-shop me-1"></i>Marketplace
|
||||
</a>
|
||||
<a class="nav-link active" href="/orders">
|
||||
<i class="bi bi-list-ul me-1"></i>My Orders
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/marketplace" class="text-decoration-none">Marketplace</a></li>
|
||||
<li class="breadcrumb-item"><a href="/orders" class="text-decoration-none">Orders</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Order Details</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if order %}
|
||||
<!-- Order Header -->
|
||||
<div class="order-header p-4 mb-4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h1 class="h2 mb-2">
|
||||
<i class="bi bi-receipt me-2"></i>Order #{{ order.order_id }}
|
||||
</h1>
|
||||
<p class="mb-0 text-muted">
|
||||
<i class="bi bi-calendar me-1"></i>Placed on {{ order.created_at }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<span class="status-badge status-{{ order.status|lower }}">
|
||||
<i class="bi bi-check-circle me-1"></i>{{ order.status }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Order Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="order-details p-4 mb-4">
|
||||
<h3 class="mb-4">
|
||||
<i class="bi bi-box-seam me-2"></i>Order Items
|
||||
</h3>
|
||||
|
||||
{% for item in order.items %}
|
||||
<div class="d-flex align-items-center p-3 border rounded mb-3">
|
||||
<div class="me-3">
|
||||
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 50px; height: 50px;">
|
||||
{% if item.product_category == "compute" %}
|
||||
<i class="bi bi-cpu text-primary"></i>
|
||||
{% elif item.product_category == "hardware" %}
|
||||
<i class="bi bi-hdd-rack text-success"></i>
|
||||
{% elif item.product_category == "gateways" %}
|
||||
<i class="bi bi-globe text-info"></i>
|
||||
{% elif item.product_category == "applications" %}
|
||||
<i class="bi bi-app text-warning"></i>
|
||||
{% elif item.product_category == "services" %}
|
||||
<i class="bi bi-person-workspace text-secondary"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-box text-muted"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<h6 class="mb-1">{{ item.product_name }}</h6>
|
||||
<small class="text-muted">{{ item.provider_name }}</small>
|
||||
<div class="mt-1">
|
||||
<span class="badge bg-light text-dark">Qty: {{ item.quantity }}</span>
|
||||
<span class="badge bg-secondary ms-1">{{ item.product_category|title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="fw-bold">{{ item.unit_price }}</div>
|
||||
<small class="text-muted">per unit</small>
|
||||
<div class="text-primary fw-bold">{{ item.total_price }}</div>
|
||||
<small class="text-muted">total</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
<!-- Order Summary -->
|
||||
<div class="border-top pt-3 mt-4">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Payment Method:</strong>
|
||||
<div>{{ order.payment_method }}</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong class="text-muted">Currency:</strong>
|
||||
<div>{{ order.currency }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span>{{ order.subtotal }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Platform fee:</span>
|
||||
<span class="text-muted">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="fw-bold fs-5">Total:</span>
|
||||
<span class="fw-bold text-primary fs-4">{{ order.total }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-gear me-2"></i>Order Actions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/orders" class="btn btn-primary">
|
||||
<i class="bi bi-arrow-left me-2"></i>Back to Orders
|
||||
</a>
|
||||
<a href="/marketplace" class="btn btn-outline-primary">
|
||||
<i class="bi bi-shop me-2"></i>Continue Shopping
|
||||
</a>
|
||||
<button class="btn btn-outline-secondary js-print">
|
||||
<i class="bi bi-printer me-2"></i>Print Order
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6 class="mb-3">Need Help?</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/docs" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-book me-1"></i>Docs
|
||||
</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-success" target="_blank">
|
||||
<i class="bi bi-chat-dots me-1"></i>Live Chat
|
||||
</a>
|
||||
<a href="mailto:support@threefold.io" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-envelope me-1"></i>Email Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Status Timeline -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="mb-0">
|
||||
<i class="bi bi-clock-history me-2"></i>Order Timeline
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="timeline">
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-check-circle-fill text-success fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Order Placed</div>
|
||||
<small class="text-muted">{{ order.created_at }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% if order.status == "Confirmed" %}
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-check-circle-fill text-success fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">Payment Confirmed</div>
|
||||
<small class="text-muted">Payment processed successfully</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex mb-3">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-circle text-muted fs-5"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-muted">Deployment</div>
|
||||
<small class="text-muted">Resources being deployed</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-exclamation-triangle fs-1 text-warning mb-3"></i>
|
||||
<h3>Order Not Found</h3>
|
||||
<p class="text-muted">The requested order could not be found.</p>
|
||||
<a href="/orders" class="btn btn-primary">View All Orders</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script type="application/json" id="order-detail-data">{}</script>
|
||||
<script src="/static/js/print-utils.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
210
src/views/marketplace/order_invoice.html
Normal file
210
src/views/marketplace/order_invoice.html
Normal file
@@ -0,0 +1,210 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Order Invoice - Project Mycelium</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body { background-color: #f8f9fa; }
|
||||
.navbar-brand img { height: 30px; }
|
||||
.invoice-header {
|
||||
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
||||
border: 2px solid #2196f3;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.invoice-details {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
.invoice-number { font-size: 1.5rem; font-weight: bold; color: #2196f3; }
|
||||
.card { border: none; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
|
||||
.btn-primary { background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%); border: none; }
|
||||
.btn-primary:hover { background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%); }
|
||||
.invoice-table th { background-color: #f8f9fa; border-top: none; }
|
||||
.total-amount { font-size: 2rem; font-weight: bold; color: #2196f3; }
|
||||
@media print {
|
||||
.no-print { display: none !important; }
|
||||
body { background-color: white !important; }
|
||||
.card, .invoice-details { box-shadow: none !important; border: 1px solid #dee2e6 !important; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark no-print">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>Project Mycelium</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/marketplace">
|
||||
<i class="bi bi-shop me-1"></i>Marketplace
|
||||
</a>
|
||||
<a class="nav-link" href="/orders">
|
||||
<i class="bi bi-list-ul me-1"></i>My Orders
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4 no-print">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/marketplace" class="text-decoration-none">Marketplace</a></li>
|
||||
<li class="breadcrumb-item"><a href="/orders" class="text-decoration-none">Orders</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Order Invoice</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if order %}
|
||||
<!-- Invoice Header -->
|
||||
<div class="invoice-header p-4 mb-4">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h1 class="h2 mb-2">
|
||||
<i class="bi bi-receipt me-2"></i>THREEFOLD MARKETPLACE INVOICE
|
||||
</h1>
|
||||
<div class="invoice-number">INV-{{ order.order_id }}</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-md-end">
|
||||
<div class="mb-2"><strong>Invoice Date:</strong> {{ invoice_date }}</div>
|
||||
<div><strong>Due Date:</strong> {{ due_date }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Invoice Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="invoice-details p-4 mb-4">
|
||||
<!-- Seller and Bill To -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">SOLD BY:</h6>
|
||||
<div class="fw-bold">Project Mycelium</div>
|
||||
<div>support@threefold.io</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-2">BILL TO:</h6>
|
||||
{% if user %}
|
||||
<div class="fw-bold">{{ user.email }}</div>
|
||||
{% if user.name %}<div>{{ user.name }}</div>{% endif %}
|
||||
{% if user.country %}<div>{{ user.country }}</div>{% endif %}
|
||||
{% else %}
|
||||
<div class="fw-bold">Account Holder</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Items Table -->
|
||||
<div class="mb-4">
|
||||
<h6 class="text-muted mb-3">ITEMS:</h6>
|
||||
<table class="table invoice-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th class="text-center">Qty</th>
|
||||
<th class="text-center">Unit Price</th>
|
||||
<th class="text-end">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in order.items %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="fw-semibold">{{ item.product_name }}</div>
|
||||
<small class="text-muted">{{ item.provider_name }} • {{ item.product_category|title }}</small>
|
||||
</td>
|
||||
<td class="text-center">{{ item.quantity }}</td>
|
||||
<td class="text-center">{{ item.unit_price }}</td>
|
||||
<td class="text-end">{{ item.total_price }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Totals -->
|
||||
<div class="border-top pt-4 mt-4">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="text-muted mb-3">PAYMENT DETAILS:</h6>
|
||||
<p class="mb-2">Payment Method: <strong>{{ order.payment_method }}</strong></p>
|
||||
<p class="mb-2">Currency: <strong>{{ order.currency }}</strong></p>
|
||||
<p class="mb-0">Invoice generated: <small class="text-muted">{{ generated_date }}</small></p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="text-md-end">
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Subtotal:</span>
|
||||
<span>{{ order.subtotal }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span class="text-muted">Platform fee:</span>
|
||||
<span class="text-muted">Free</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span class="fw-bold fs-5">TOTAL AMOUNT:</span>
|
||||
<span class="total-amount">{{ order.total }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions Sidebar -->
|
||||
<div class="col-lg-4 no-print">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0"><i class="bi bi-gear me-2"></i>Invoice Actions</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/orders/{{ order.order_id }}" class="btn btn-primary">
|
||||
<i class="bi bi-arrow-left me-2"></i>Back to Order
|
||||
</a>
|
||||
<button class="btn btn-success js-print">
|
||||
<i class="bi bi-printer me-2"></i>Print Invoice
|
||||
</button>
|
||||
</div>
|
||||
<hr>
|
||||
<h6 class="mb-3">Need Help?</h6>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/docs" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-book me-1"></i>Documentation
|
||||
</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-success" target="_blank">
|
||||
<i class="bi bi-chat-dots me-1"></i>Live Chat
|
||||
</a>
|
||||
<a href="mailto:support@threefold.io" class="btn btn-sm btn-outline-secondary">
|
||||
<i class="bi bi-envelope me-1"></i>Email Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-exclamation-triangle fs-1 text-warning mb-3"></i>
|
||||
<h3>Order Not Found</h3>
|
||||
<p class="text-muted">The requested order could not be found.</p>
|
||||
<a href="/orders" class="btn btn-primary">View All Orders</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script type="application/json" id="invoice-data">{}</script>
|
||||
<script src="/static/js/print-utils.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
395
src/views/marketplace/orders.html
Normal file
395
src/views/marketplace/orders.html
Normal file
@@ -0,0 +1,395 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>My Orders - Project Mycelium</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.0/font/bootstrap-icons.css" rel="stylesheet">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.navbar-brand img {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.order-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 20px;
|
||||
font-weight: bold;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
border: 1px solid #ffeaa7;
|
||||
}
|
||||
|
||||
.status-confirmed {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
background: #cce5ff;
|
||||
color: #004085;
|
||||
border: 1px solid #99d6ff;
|
||||
}
|
||||
|
||||
.status-deployed {
|
||||
background: #d1ecf1;
|
||||
color: #0c5460;
|
||||
border: 1px solid #bee5eb;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.status-cancelled {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.filter-card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
position: sticky;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.breadcrumb-item + .breadcrumb-item::before {
|
||||
content: "›";
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #0d6efd 0%, #0b5ed7 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: linear-gradient(135deg, #0b5ed7 0%, #0a58ca 100%);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container">
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
<img src="/static/images/logo_dark.png" alt="ThreeFold Logo" class="me-2">
|
||||
<span>Project Mycelium</span>
|
||||
</a>
|
||||
<div class="navbar-nav ms-auto">
|
||||
<a class="nav-link" href="/marketplace">
|
||||
<i class="bi bi-shop me-1"></i>Marketplace
|
||||
</a>
|
||||
<a class="nav-link" href="/cart">
|
||||
<i class="bi bi-cart3 me-1"></i>Cart
|
||||
</a>
|
||||
<a class="nav-link active" href="/orders">
|
||||
<i class="bi bi-list-ul me-1"></i>My Orders
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container py-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/" class="text-decoration-none">Home</a></li>
|
||||
<li class="breadcrumb-item"><a href="/marketplace" class="text-decoration-none">Marketplace</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">My Orders</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-4 border-bottom">
|
||||
<h1 class="h2 mb-0">
|
||||
<i class="bi bi-list-ul me-2 text-primary"></i>My Orders
|
||||
</h1>
|
||||
<div class="btn-toolbar">
|
||||
<a href="/marketplace" class="btn btn-primary">
|
||||
<i class="bi bi-shop me-1"></i>Continue Shopping
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<!-- Orders List -->
|
||||
<div class="col-lg-8">
|
||||
{% if orders and orders|length > 0 %}
|
||||
{% for order in orders %}
|
||||
<div class="order-card card mb-4">
|
||||
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h5 class="mb-1">Order #{{ order.order_id }}</h5>
|
||||
<small class="text-muted">Placed on {{ order.created_at }}</small>
|
||||
</div>
|
||||
<span class="status-badge status-{{ order.status|lower }}">
|
||||
{% if order.status == "Pending" %}
|
||||
<i class="bi bi-clock me-1"></i>
|
||||
{% elif order.status == "Confirmed" %}
|
||||
<i class="bi bi-check-circle me-1"></i>
|
||||
{% elif order.status == "Processing" %}
|
||||
<i class="bi bi-gear me-1"></i>
|
||||
{% elif order.status == "Deployed" %}
|
||||
<i class="bi bi-cloud-check me-1"></i>
|
||||
{% elif order.status == "Completed" %}
|
||||
<i class="bi bi-check-all me-1"></i>
|
||||
{% elif order.status == "Cancelled" %}
|
||||
<i class="bi bi-x-circle me-1"></i>
|
||||
{% endif %}
|
||||
{{ order.status }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<h6 class="mb-3">Items ({{ order.items|length }})</h6>
|
||||
{% for item in order.items %}
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="me-3">
|
||||
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
|
||||
{% if item.product_category == "compute" %}
|
||||
<i class="bi bi-cpu text-primary"></i>
|
||||
{% elif item.product_category == "hardware" %}
|
||||
<i class="bi bi-hdd-rack text-success"></i>
|
||||
{% elif item.product_category == "gateways" %}
|
||||
<i class="bi bi-globe text-info"></i>
|
||||
{% elif item.product_category == "applications" %}
|
||||
<i class="bi bi-app text-warning"></i>
|
||||
{% elif item.product_category == "services" %}
|
||||
<i class="bi bi-person-workspace text-secondary"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-box text-muted"></i>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="fw-bold">{{ item.product_name }}</div>
|
||||
<small class="text-muted">{{ item.provider_name }} • Qty: {{ item.quantity }}</small>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="fw-bold">{{ item.total_price }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="text-end">
|
||||
<div class="mb-2">
|
||||
<strong class="text-muted">Total Amount:</strong>
|
||||
</div>
|
||||
<div class="h4 text-primary mb-3">{{ order.total }}</div>
|
||||
<div class="mb-2">
|
||||
<strong class="text-muted">Payment:</strong>
|
||||
</div>
|
||||
<div class="mb-3">{{ order.payment_method }}</div>
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/orders/{{ order.order_id }}" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-eye me-1"></i>View Details
|
||||
</a>
|
||||
{% if order.status == "Deployed" or order.status == "Completed" %}
|
||||
<a href="#" class="btn btn-outline-success btn-sm">
|
||||
<i class="bi bi-play-circle me-1"></i>Access Resources
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if order.confirmation_number %}
|
||||
<div class="card-footer bg-light">
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-shield-check me-1"></i>
|
||||
Confirmation: <strong>{{ order.confirmation_number }}</strong>
|
||||
</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<!-- Empty State -->
|
||||
<div class="empty-state p-5 text-center">
|
||||
<i class="bi bi-bag-x display-1 text-muted mb-4"></i>
|
||||
<h3 class="text-muted mb-3">No orders yet</h3>
|
||||
<p class="text-muted mb-4">
|
||||
You haven't placed any orders yet. Explore our marketplace to find amazing ThreeFold resources and services.
|
||||
</p>
|
||||
<a href="/marketplace" class="btn btn-primary btn-lg">
|
||||
<i class="bi bi-shop me-2"></i>Browse Marketplace
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Filters & Info Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<div class="filter-card p-4 mb-4">
|
||||
<h5 class="mb-3">
|
||||
<i class="bi bi-funnel me-2"></i>Filter Orders
|
||||
</h5>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="statusFilter" class="form-label">Order Status</label>
|
||||
<select class="form-select" id="statusFilter">
|
||||
<option value="">All Statuses</option>
|
||||
<option value="pending">Pending</option>
|
||||
<option value="confirmed">Confirmed</option>
|
||||
<option value="processing">Processing</option>
|
||||
<option value="deployed">Deployed</option>
|
||||
<option value="completed">Completed</option>
|
||||
<option value="cancelled">Cancelled</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="dateRange" class="form-label">Date Range</label>
|
||||
<select class="form-select" id="dateRange">
|
||||
<option value="">All Time</option>
|
||||
<option value="7">Last 7 days</option>
|
||||
<option value="30">Last 30 days</option>
|
||||
<option value="90">Last 3 months</option>
|
||||
<option value="365">Last year</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="d-grid">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Statistics -->
|
||||
<div class="filter-card p-4 mb-4">
|
||||
<h6 class="mb-3">
|
||||
<i class="bi bi-graph-up me-2"></i>Order Summary
|
||||
</h6>
|
||||
|
||||
{% if orders %}
|
||||
<div class="row text-center">
|
||||
<div class="col-6 mb-3">
|
||||
<div class="h4 text-primary">{{ orders|length }}</div>
|
||||
<small class="text-muted">Total Orders</small>
|
||||
</div>
|
||||
<div class="col-6 mb-3">
|
||||
<div class="h4 text-success">
|
||||
{% set completed_count = 0 %}
|
||||
{% for order in orders %}
|
||||
{% if order.status == "Completed" %}
|
||||
{% set completed_count = completed_count + 1 %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ completed_count }}
|
||||
</div>
|
||||
<small class="text-muted">Completed</small>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="h4 text-info">
|
||||
{% set active_count = 0 %}
|
||||
{% for order in orders %}
|
||||
{% if order.status in ["Pending", "Confirmed", "Processing", "Deployed"] %}
|
||||
{% set active_count = active_count + 1 %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ active_count }}
|
||||
</div>
|
||||
<small class="text-muted">Active</small>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="h4 text-warning">
|
||||
{% set pending_count = 0 %}
|
||||
{% for order in orders %}
|
||||
{% if order.status == "Pending" %}
|
||||
{% set pending_count = pending_count + 1 %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ pending_count }}
|
||||
</div>
|
||||
<small class="text-muted">Pending</small>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center text-muted">
|
||||
<i class="bi bi-graph-up fs-1 mb-2"></i>
|
||||
<div>No order data available</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="filter-card p-4">
|
||||
<h6 class="mb-3">
|
||||
<i class="bi bi-lightning me-2"></i>Quick Actions
|
||||
</h6>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<a href="/marketplace" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-shop me-1"></i>Browse Products
|
||||
</a>
|
||||
<a href="/cart" class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-cart3 me-1"></i>View Cart
|
||||
</a>
|
||||
<a href="/dashboard" class="btn btn-outline-info btn-sm">
|
||||
<i class="bi bi-speedometer2 me-1"></i>Dashboard
|
||||
</a>
|
||||
<button class="btn btn-outline-success btn-sm" data-action="export-orders">
|
||||
<i class="bi bi-download me-1"></i>Export Orders
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<h6 class="mb-2">Need Help?</h6>
|
||||
<div class="d-grid gap-1">
|
||||
<a href="/docs" class="btn btn-sm btn-outline-primary">
|
||||
<i class="bi bi-book me-1"></i>Docs
|
||||
</a>
|
||||
<a href="https://threefoldfaq.crisp.help/en/" class="btn btn-sm btn-outline-success" target="_blank">
|
||||
<i class="bi bi-chat-dots me-1"></i>Contact Support
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script type="application/json" id="orders-data">{}</script>
|
||||
<script src="/static/js/orders.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
293
src/views/marketplace/product_detail.html
Normal file
293
src/views/marketplace/product_detail.html
Normal file
@@ -0,0 +1,293 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}{{ product.product.name }} - Project Mycelium{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/marketplace">Marketplace</a></li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/marketplace/{{ product.product.category_id }}">
|
||||
{{ product.product.category_id | title }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ product.product.name }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<!-- Product Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<!-- Product Header -->
|
||||
<div class="d-flex justify-content-between align-items-start mb-4">
|
||||
<div>
|
||||
<h1 class="h2 mb-2">{{ product.product.name }}</h1>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<span class="badge bg-primary me-2">{{ product.product.category_id | title }}</span>
|
||||
{% if product.product.metadata.featured %}
|
||||
<span class="badge bg-warning me-2">Featured</span>
|
||||
{% endif %}
|
||||
{% if product.product.availability == "Available" %}
|
||||
<span class="badge bg-success">Available</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ product.product.availability }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="text-muted mb-0">
|
||||
<i class="bi bi-building me-1"></i>
|
||||
{{ product.product.provider_name }}
|
||||
{% if product.product.metadata.location %}
|
||||
<span class="ms-3">
|
||||
<i class="bi bi-geo-alt me-1"></i>
|
||||
{{ product.product.metadata.location }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="price-display">
|
||||
<div class="h3 text-primary mb-0">{{ product.formatted_price }}</div>
|
||||
{% if product.price.display_currency != product.price.base_currency %}
|
||||
<small class="text-muted">
|
||||
({{ product.price.base_amount }} {{ product.price.base_currency }})
|
||||
</small>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Product Description -->
|
||||
<div class="mb-4">
|
||||
<h5>Description</h5>
|
||||
<p>{{ product.product.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Product Specifications -->
|
||||
{% if product.product.attributes %}
|
||||
<div class="mb-4">
|
||||
<h5>Specifications</h5>
|
||||
<div class="row">
|
||||
{% for key, attr in product.product.attributes %}
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="spec-item">
|
||||
{% if key == "cpu_cores" %}
|
||||
<i class="bi bi-cpu me-2 text-primary"></i>
|
||||
{% elif key == "memory_gb" %}
|
||||
<i class="bi bi-memory me-2 text-primary"></i>
|
||||
{% elif key == "storage_gb" %}
|
||||
<i class="bi bi-hdd me-2 text-primary"></i>
|
||||
{% elif key == "bandwidth_mbps" %}
|
||||
<i class="bi bi-speedometer2 me-2 text-primary"></i>
|
||||
{% elif key == "uptime_percentage" %}
|
||||
<i class="bi bi-check-circle me-2 text-success"></i>
|
||||
{% else %}
|
||||
<i class="bi bi-info-circle me-2 text-info"></i>
|
||||
{% endif %}
|
||||
<strong>{{ key | replace(from="_", to=" ") | title }}:</strong>
|
||||
<span class="ms-2">
|
||||
{% if key == "memory_gb" or key == "storage_gb" %}
|
||||
{{ attr.value }} GB
|
||||
{% elif key == "bandwidth_mbps" %}
|
||||
{{ attr.value }} Mbps
|
||||
{% elif key == "uptime_percentage" %}
|
||||
{{ attr.value }}%
|
||||
{% else %}
|
||||
{{ attr.value }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Product Tags -->
|
||||
{% if product.product.metadata.tags %}
|
||||
<div class="mb-4">
|
||||
<h6>Tags</h6>
|
||||
{% for tag in product.product.metadata.tags %}
|
||||
<span class="badge bg-light text-dark me-1">{{ tag }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<!-- Add to Cart Card -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Purchase Options</h5>
|
||||
|
||||
<!-- Quantity Selector -->
|
||||
<div class="mb-3">
|
||||
<label for="quantity" class="form-label">Quantity</label>
|
||||
<div class="input-group">
|
||||
<button class="btn btn-outline-secondary" type="button" id="decreaseQty">-</button>
|
||||
<input type="number" class="form-control text-center" id="quantity" value="1" min="1" max="10">
|
||||
<button class="btn btn-outline-secondary" type="button" id="increaseQty">+</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Total Price Display -->
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Total:</span>
|
||||
<span class="fw-bold text-primary" id="totalPrice">{{ product.formatted_price }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy Now Button -->
|
||||
<button class="btn btn-success w-100 mb-2 buy-now-btn"
|
||||
data-product-id="{{ product.product.id }}"
|
||||
data-product-name="{{ product.product.name }}"
|
||||
data-unit-price="{{ product.product.base_price }}"
|
||||
data-category="{{ product.product.category_id }}"
|
||||
data-provider-id="{{ product.product.provider_id }}"
|
||||
data-provider-name="{{ product.product.provider_name }}"
|
||||
title="Buy instantly with your wallet balance">
|
||||
<i class="bi bi-lightning-charge me-2"></i>Buy Now
|
||||
</button>
|
||||
|
||||
<!-- Add to Cart Button -->
|
||||
<button class="btn btn-primary w-100 mb-2" id="addToCartBtn"
|
||||
data-product-id="{{ product.product.id }}"
|
||||
data-product-name="{{ product.product.name }}"
|
||||
data-unit-price="{{ product.price.display_amount }}"
|
||||
data-currency="{{ product.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus me-2"></i>Add to Cart
|
||||
</button>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="d-grid gap-2">
|
||||
<button class="btn btn-outline-secondary btn-sm">
|
||||
<i class="bi bi-heart me-1"></i>Add to Wishlist
|
||||
</button>
|
||||
<button class="btn btn-outline-info btn-sm">
|
||||
<i class="bi bi-share me-1"></i>Share Product
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Provider Information -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Provider Information</h6>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="provider-avatar me-3">
|
||||
<div class="bg-primary text-white rounded-circle d-flex align-items-center justify-content-center"
|
||||
style="width: 40px; height: 40px;">
|
||||
{{ product.product.provider_name | slice(end=1) | upper }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="fw-bold">{{ product.product.provider_name }}</div>
|
||||
{% if product.product.metadata.rating %}
|
||||
<div class="text-muted small">
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star-fill text-warning"></i>
|
||||
<i class="bi bi-star text-muted"></i>
|
||||
<span class="ms-1">{{ product.product.metadata.rating }}/5 ({{ product.product.metadata.review_count }} reviews)</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<p class="small text-muted mb-0">
|
||||
Trusted provider in the ThreeFold ecosystem with verified infrastructure.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Currency Selector -->
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">Currency</h6>
|
||||
<select class="form-select" id="currencySelector">
|
||||
{% for currency in currencies %}
|
||||
<option value="{{ currency.code }}"
|
||||
{% if currency.code == user_currency %}selected{% endif %}>
|
||||
{{ currency.symbol }} {{ currency.name }} ({{ currency.code }})
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recommendations Section -->
|
||||
{% if recommendations and recommendations | length > 0 %}
|
||||
<div class="mt-5">
|
||||
<h4 class="mb-4">Recommended Products</h4>
|
||||
<div class="row">
|
||||
{% for rec in recommendations %}
|
||||
<div class="col-lg-3 col-md-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<h6 class="card-title">
|
||||
<a href="/products/{{ rec.product.id }}" class="text-decoration-none">
|
||||
{{ rec.product.name }}
|
||||
</a>
|
||||
</h6>
|
||||
<p class="card-text small text-muted">{{ rec.product.description | truncate(length=80) }}</p>
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-primary fw-bold">{{ rec.formatted_price }}</span>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-success btn-sm buy-now-btn"
|
||||
data-product-id="{{ rec.product.id }}"
|
||||
data-product-name="{{ rec.product.name }}"
|
||||
data-unit-price="{{ rec.price.display_amount }}"
|
||||
data-currency="{{ rec.price.display_currency }}"
|
||||
data-category="{{ rec.product.category_id }}">
|
||||
<i class="bi bi-lightning-fill"></i>
|
||||
</button>
|
||||
<button class="btn btn-outline-primary btn-sm add-to-cart-btn"
|
||||
data-product-id="{{ rec.product.id }}"
|
||||
data-product-name="{{ rec.product.name }}"
|
||||
data-unit-price="{{ rec.price.display_amount }}"
|
||||
data-currency="{{ rec.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus"></i>
|
||||
</button>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.spec-item {
|
||||
padding: 0.5rem 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.spec-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.price-display {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.provider-avatar {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="/static/js/product-detail.js"></script>
|
||||
{% endblock %}
|
||||
74
src/views/marketplace/product_detail_step1.html
Normal file
74
src/views/marketplace/product_detail_step1.html
Normal file
@@ -0,0 +1,74 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}{{ product.product.name }} - Project Mycelium{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/marketplace">Marketplace</a></li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/marketplace/{{ product.product.category_id }}">
|
||||
{{ product.product.category_id | title }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ product.product.name }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<!-- Product Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<!-- Product Header -->
|
||||
<div class="d-flex justify-content-between align-items-start mb-4">
|
||||
<div>
|
||||
<h1 class="h2 mb-2">{{ product.product.name }}</h1>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<span class="badge bg-primary me-2">{{ product.product.category_id | title }}</span>
|
||||
{% if product.product.metadata.featured %}
|
||||
<span class="badge bg-warning me-2">Featured</span>
|
||||
{% endif %}
|
||||
<span class="badge bg-success">{{ product.product.availability }}</span>
|
||||
</div>
|
||||
<p class="text-muted mb-0">
|
||||
<i class="bi bi-building me-1"></i>
|
||||
{{ product.product.provider_name }}
|
||||
{% if product.product.metadata.location %}
|
||||
<span class="ms-3">
|
||||
<i class="bi bi-geo-alt me-1"></i>
|
||||
{{ product.product.metadata.location }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="price-display">
|
||||
<div class="h3 text-primary mb-0">{{ product.formatted_price }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Product Description -->
|
||||
<div class="mb-4">
|
||||
<h5>Description</h5>
|
||||
<p>{{ product.product.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Purchase Options</h5>
|
||||
<button class="btn btn-primary w-100">Add to Cart</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
120
src/views/marketplace/product_detail_step2.html
Normal file
120
src/views/marketplace/product_detail_step2.html
Normal file
@@ -0,0 +1,120 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}{{ product.product.name }} - Project Mycelium{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<!-- Breadcrumb -->
|
||||
<nav aria-label="breadcrumb" class="mb-4">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="/marketplace">Marketplace</a></li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="/marketplace/{{ product.product.category_id }}">
|
||||
{{ product.product.category_id | title }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ product.product.name }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div class="row">
|
||||
<!-- Product Details -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<!-- Product Header -->
|
||||
<div class="d-flex justify-content-between align-items-start mb-4">
|
||||
<div>
|
||||
<h1 class="h2 mb-2">{{ product.product.name }}</h1>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<span class="badge bg-primary me-2">{{ product.product.category_id | title }}</span>
|
||||
{% if product.product.metadata.featured %}
|
||||
<span class="badge bg-warning me-2">Featured</span>
|
||||
{% endif %}
|
||||
<span class="badge bg-success">{{ product.product.availability }}</span>
|
||||
</div>
|
||||
<p class="text-muted mb-0">
|
||||
<i class="bi bi-building me-1"></i>
|
||||
{{ product.product.provider_name }}
|
||||
{% if product.product.metadata.location %}
|
||||
<span class="ms-3">
|
||||
<i class="bi bi-geo-alt me-1"></i>
|
||||
{{ product.product.metadata.location }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-end">
|
||||
<div class="price-display">
|
||||
<div class="h3 text-primary mb-0">{{ product.formatted_price }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Product Description -->
|
||||
<div class="mb-4">
|
||||
<h5>Description</h5>
|
||||
<p>{{ product.product.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Product Specifications -->
|
||||
{% if product.product.attributes %}
|
||||
<div class="mb-4">
|
||||
<h5>Specifications</h5>
|
||||
<div class="row">
|
||||
{% for key, attr in product.product.attributes %}
|
||||
<div class="col-md-6 mb-3">
|
||||
<div class="spec-item">
|
||||
<strong>{{ key | replace(from="_", to=" ") | title }}:</strong>
|
||||
<span class="ms-2">{{ attr.value }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<!-- Add to Cart Card -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Purchase Options</h5>
|
||||
|
||||
<!-- Quantity Selector -->
|
||||
<div class="mb-3">
|
||||
<label for="quantity" class="form-label">Quantity</label>
|
||||
<div class="input-group">
|
||||
<button class="btn btn-outline-secondary" type="button" id="decreaseQty">-</button>
|
||||
<input type="number" class="form-control text-center" id="quantity" value="1" min="1" max="10">
|
||||
<button class="btn btn-outline-secondary" type="button" id="increaseQty">+</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Total Price Display -->
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Total:</span>
|
||||
<span class="fw-bold text-primary" id="totalPrice">{{ product.formatted_price }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add to Cart Button -->
|
||||
<button class="btn btn-primary w-100 mb-2" id="addToCartBtn"
|
||||
data-product-id="{{ product.product.id }}"
|
||||
data-product-name="{{ product.product.name }}"
|
||||
data-unit-price="{{ product.price.display_amount }}"
|
||||
data-currency="{{ product.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus me-2"></i>Add to Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/js/product-detail-step2.js"></script>
|
||||
{% endblock %}
|
||||
337
src/views/marketplace/products.html
Normal file
337
src/views/marketplace/products.html
Normal file
@@ -0,0 +1,337 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - Products{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1>All Products</h1>
|
||||
<p class="lead mb-0">
|
||||
{% if search_query.q %}
|
||||
Search results for "{{ search_query.q }}"
|
||||
{% elif search_query.category %}
|
||||
{{ search_query.category | title }} Products
|
||||
{% else %}
|
||||
Browse all available products and services
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-muted">
|
||||
{% if response.total_count > 0 %}
|
||||
Showing {{ response.products | length }} of {{ response.total_count }} products
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search and Filter Section -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<form method="GET" class="row g-3">
|
||||
<!-- Search Query -->
|
||||
<div class="col-md-4">
|
||||
<label for="searchQuery" class="form-label">Search Products</label>
|
||||
<input type="text" class="form-control" id="searchQuery" name="q"
|
||||
value="{{ search_query.q or '' }}" placeholder="Search products...">
|
||||
</div>
|
||||
|
||||
<!-- Category Filter -->
|
||||
<div class="col-md-2">
|
||||
<label for="categoryFilter" class="form-label">Category</label>
|
||||
<select id="categoryFilter" name="category" class="form-select">
|
||||
<option value="">All Categories</option>
|
||||
{% for category in response.categories %}
|
||||
<option value="{{ category.id }}"
|
||||
{% if search_query.category == category.id %}selected{% endif %}>
|
||||
{{ category.display_name }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Price Range -->
|
||||
<div class="col-md-2">
|
||||
<label for="minPrice" class="form-label">Min Price</label>
|
||||
<input type="number" class="form-control" id="minPrice" name="min_price"
|
||||
value="{{ search_query.min_price or '' }}" placeholder="0">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label for="maxPrice" class="form-label">Max Price</label>
|
||||
<input type="number" class="form-control" id="maxPrice" name="max_price"
|
||||
value="{{ search_query.max_price or '' }}" placeholder="1000">
|
||||
</div>
|
||||
|
||||
<!-- Provider Filter -->
|
||||
<div class="col-md-2">
|
||||
<label for="providerFilter" class="form-label">Provider</label>
|
||||
<input type="text" class="form-control" id="providerFilter" name="provider"
|
||||
value="{{ search_query.provider or '' }}" placeholder="Provider name">
|
||||
</div>
|
||||
|
||||
<!-- Search Button -->
|
||||
<div class="col-md-12 d-flex justify-content-between align-items-end">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-search me-1"></i>Search
|
||||
</button>
|
||||
<a href="/products" class="btn btn-outline-secondary">Clear Filters</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Results Section -->
|
||||
{% if response.products and response.products | length > 0 %}
|
||||
<!-- Sort Options -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div class="btn-group" role="group" aria-label="View options">
|
||||
<input type="radio" class="btn-check" name="view-mode" id="grid-view" checked>
|
||||
<label class="btn btn-outline-secondary" for="grid-view">
|
||||
<i class="bi bi-grid-3x3-gap"></i> Grid
|
||||
</label>
|
||||
<input type="radio" class="btn-check" name="view-mode" id="list-view">
|
||||
<label class="btn btn-outline-secondary" for="list-view">
|
||||
<i class="bi bi-list"></i> List
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
Sort by: Price (Low to High)
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a class="dropdown-item" href="#">Price (Low to High)</a></li>
|
||||
<li><a class="dropdown-item" href="#">Price (High to Low)</a></li>
|
||||
<li><a class="dropdown-item" href="#">Name (A-Z)</a></li>
|
||||
<li><a class="dropdown-item" href="#">Provider</a></li>
|
||||
<li><a class="dropdown-item" href="#">Featured First</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Products Grid -->
|
||||
<div id="products-grid" class="row">
|
||||
{% for product_data in response.products %}
|
||||
<div class="col-lg-4 col-md-6 mb-4">
|
||||
<div class="card h-100 product-card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<h5 class="card-title">
|
||||
<a href="/products/{{ product_data.product.id }}" class="text-decoration-none text-dark">
|
||||
{{ product_data.product.name }}
|
||||
</a>
|
||||
</h5>
|
||||
{% if product_data.product.metadata.featured %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% elif product_data.product.availability == "Available" %}
|
||||
<span class="badge bg-success">Available</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ product_data.product.availability }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<span class="badge bg-primary">{{ product_data.product.category_id | title }}</span>
|
||||
{% if product_data.product.metadata.location %}
|
||||
<span class="badge bg-light text-dark ms-1">{{ product_data.product.metadata.location }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<p class="card-text text-muted small">{{ product_data.product.description | truncate(length=100) }}</p>
|
||||
|
||||
<!-- Key Specifications -->
|
||||
{% if product_data.product.attributes %}
|
||||
<div class="mb-3">
|
||||
<div class="row text-center">
|
||||
{% if product_data.product.attributes.cpu_cores %}
|
||||
<div class="col-4">
|
||||
<div class="spec-badge">
|
||||
<i class="bi bi-cpu text-primary"></i>
|
||||
<div class="small">{{ product_data.product.attributes.cpu_cores.value }} cores</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.memory_gb %}
|
||||
<div class="col-4">
|
||||
<div class="spec-badge">
|
||||
<i class="bi bi-memory text-primary"></i>
|
||||
<div class="small">{{ product_data.product.attributes.memory_gb.value }} GB</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.storage_gb %}
|
||||
<div class="col-4">
|
||||
<div class="spec-badge">
|
||||
<i class="bi bi-hdd text-primary"></i>
|
||||
<div class="small">{{ product_data.product.attributes.storage_gb.value }} GB</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="text-muted small mb-3">
|
||||
<i class="bi bi-building me-1"></i>{{ product_data.product.provider_name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="price-info">
|
||||
<div class="fw-bold text-primary">{{ product_data.price.formatted_display }}</div>
|
||||
{% if product_data.price.display_currency != "USD" %}
|
||||
<div class="small text-muted">≈ ${{ product_data.product.base_price }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-success btn-sm buy-now-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-category="{{ product_data.product.category_id }}"
|
||||
data-unit-price="{{ product_data.product.base_price }}"
|
||||
data-provider-id="{{ product_data.product.provider_id }}"
|
||||
data-provider-name="{{ product_data.product.provider_name }}"
|
||||
title="Buy instantly with your wallet balance">
|
||||
<i class="bi bi-lightning-fill"></i>
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm add-to-cart-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus"></i>
|
||||
</button>
|
||||
<a href="/products/{{ product_data.product.id }}" class="btn btn-outline-primary btn-sm">View Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Products List View (Hidden by default) -->
|
||||
<div id="products-list" class="d-none">
|
||||
{% for product_data in response.products %}
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
<h5 class="mb-1">
|
||||
<a href="/products/{{ product_data.product.id }}" class="text-decoration-none text-dark">
|
||||
{{ product_data.product.name }}
|
||||
</a>
|
||||
</h5>
|
||||
{% if product_data.product.metadata.featured %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% elif product_data.product.availability == "Available" %}
|
||||
<span class="badge bg-success">Available</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ product_data.product.availability }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<p class="text-muted mb-2">{{ product_data.product.description | truncate(length=150) }}</p>
|
||||
<div class="text-muted small">
|
||||
<span class="badge bg-primary me-2">{{ product_data.product.category_id | title }}</span>
|
||||
<i class="bi bi-building me-1"></i>{{ product_data.product.provider_name }}
|
||||
{% if product_data.product.metadata.location %}
|
||||
<span class="ms-2">
|
||||
<i class="bi bi-geo-alt me-1"></i>{{ product_data.product.metadata.location }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<div class="fw-bold text-primary fs-5 mb-2">{{ product_data.price.formatted_display }}</div>
|
||||
{% if product_data.price.display_currency != "USD" %}
|
||||
<div class="small text-muted">≈ ${{ product_data.product.base_price }}</div>
|
||||
{% endif %}
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-primary btn-sm add-to-cart-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus me-1"></i>Add to Cart
|
||||
</button>
|
||||
<a href="/products/{{ product_data.product.id }}" class="btn btn-outline-primary btn-sm">View Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if response.total_pages > 1 %}
|
||||
<nav aria-label="Product pages" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if response.page > 0 %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ response.page - 1 }}{% if search_query.q %}&q={{ search_query.q }}{% endif %}{% if search_query.category %}&category={{ search_query.category }}{% endif %}">Previous</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link">Previous</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for page_num in range(end=response.total_pages) %}
|
||||
<li class="page-item {% if page_num == response.page %}active{% endif %}">
|
||||
<a class="page-link" href="?page={{ page_num }}{% if search_query.q %}&q={{ search_query.q }}{% endif %}{% if search_query.category %}&category={{ search_query.category }}{% endif %}">{{ page_num + 1 }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
{% if response.page < response.total_pages - 1 %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ response.page + 1 }}{% if search_query.q %}&q={{ search_query.q }}{% endif %}{% if search_query.category %}&category={{ search_query.category }}{% endif %}">Next</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="page-item disabled">
|
||||
<span class="page-link">Next</span>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<!-- No Results -->
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-search display-1 text-muted"></i>
|
||||
<h4 class="mt-3">No Products Found</h4>
|
||||
{% if search_query.q or search_query.category %}
|
||||
<p class="text-muted">Try adjusting your search criteria or browse all products.</p>
|
||||
<a href="/products" class="btn btn-primary">Browse All Products</a>
|
||||
{% else %}
|
||||
<p class="text-muted">No products are currently available.</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.product-card {
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.product-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.spec-badge {
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 0.375rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.price-info {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="/static/js/products-page.js"></script>
|
||||
{% endblock %}
|
||||
358
src/views/marketplace/services.html
Normal file
358
src/views/marketplace/services.html
Normal file
@@ -0,0 +1,358 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - Professional Services{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<h1>Professional Services</h1>
|
||||
<p class="lead">Expert services to help you succeed with ThreeFold technology and infrastructure.</p>
|
||||
|
||||
<!-- Services Introduction -->
|
||||
<div class="alert alert-info mb-4">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-people-fill fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">Professional Support & Services</h5>
|
||||
<p>Our certified experts and trusted community providers offer comprehensive services to help you deploy, manage, and optimize your ThreeFold infrastructure and applications.</p>
|
||||
<hr>
|
||||
<p class="mb-0">From initial consultation to ongoing support, we ensure your success with decentralized technology.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter and Search Section -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filter Services</h5>
|
||||
<form class="row g-3" method="GET">
|
||||
<div class="col-md-3">
|
||||
<label for="serviceTypeFilter" class="form-label">Service Type</label>
|
||||
<select name="service_type" id="serviceTypeFilter" class="form-select">
|
||||
<option value="">All Services</option>
|
||||
<option value="Consulting">Consulting</option>
|
||||
<option value="Deployment">Deployment</option>
|
||||
<option value="Support">Support</option>
|
||||
<option value="Training">Training</option>
|
||||
<option value="Development">Development</option>
|
||||
<option value="Maintenance">Maintenance</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="expertiseFilter" class="form-label">Expertise Level</label>
|
||||
<select name="expertise_level" id="expertiseFilter" class="form-select">
|
||||
<option value="">Any</option>
|
||||
<option value="Basic">Basic</option>
|
||||
<option value="Intermediate">Intermediate</option>
|
||||
<option value="Advanced">Advanced</option>
|
||||
<option value="Expert">Expert</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="minPriceFilter" class="form-label">Min Price ($)</label>
|
||||
<input type="number" name="min_price" id="minPriceFilter" class="form-control"
|
||||
value="" placeholder="0" min="0" step="5">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="maxPriceFilter" class="form-label">Max Price ($)</label>
|
||||
<input type="number" name="max_price" id="maxPriceFilter" class="form-control"
|
||||
value="" placeholder="200" min="0" step="5">
|
||||
</div>
|
||||
<div class="col-md-6 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-primary me-2">Apply Filters</button>
|
||||
<a href="/marketplace/services" class="btn btn-outline-secondary">Clear</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Services Grid -->
|
||||
<div class="row" id="services-grid">
|
||||
{% if service_products and service_products | length > 0 %}
|
||||
{% for product_data in service_products %}
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start mb-3">
|
||||
<div class="service-icon me-3">
|
||||
<i class="bi bi-gear-fill fs-2 text-primary"></i>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<h5 class="card-title mb-1">
|
||||
<a href="/products/{{ product_data.product.id }}" class="text-decoration-none text-dark">
|
||||
{{ product_data.product.name }}
|
||||
</a>
|
||||
</h5>
|
||||
{% if product_data.product.metadata.featured %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% elif product_data.product.availability == "Available" %}
|
||||
<span class="badge bg-success">Available</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ product_data.product.availability }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-muted small mb-2">
|
||||
<i class="bi bi-building me-1"></i>{{ product_data.product.provider_name }}
|
||||
{% if product_data.product.metadata.location %}
|
||||
<span class="ms-2">
|
||||
<i class="bi bi-geo-alt me-1"></i>{{ product_data.product.metadata.location }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="card-text">{{ product_data.product.description | truncate(length=150) }}</p>
|
||||
|
||||
<!-- Service Details -->
|
||||
{% if product_data.product.attributes %}
|
||||
<div class="mb-3">
|
||||
<h6 class="mb-2">Service Details:</h6>
|
||||
<div class="row">
|
||||
{% if product_data.product.attributes.duration_hours %}
|
||||
<div class="col-md-6">
|
||||
<div class="service-detail">
|
||||
<i class="bi bi-clock me-2"></i>
|
||||
<span>Duration: {{ product_data.product.attributes.duration_hours.value }} hours</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.expertise_level %}
|
||||
<div class="col-md-6">
|
||||
<div class="service-detail">
|
||||
<i class="bi bi-star me-2"></i>
|
||||
<span>Level: {{ product_data.product.attributes.expertise_level.value | title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.response_time_hours %}
|
||||
<div class="col-md-6">
|
||||
<div class="service-detail">
|
||||
<i class="bi bi-reply me-2"></i>
|
||||
<span>Response: {{ product_data.product.attributes.response_time_hours.value }}h</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.support_type %}
|
||||
<div class="col-md-6">
|
||||
<div class="service-detail">
|
||||
<i class="bi bi-headset me-2"></i>
|
||||
<span>Type: {{ product_data.product.attributes.support_type.value | title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Service Features/Tags -->
|
||||
{% if product_data.product.metadata.tags and product_data.product.metadata.tags | length > 0 %}
|
||||
<div class="mb-3">
|
||||
<h6 class="mb-2">Includes:</h6>
|
||||
<div class="d-flex flex-wrap">
|
||||
{% for tag in product_data.product.metadata.tags %}
|
||||
<span class="badge bg-light text-dark me-1 mb-1">{{ tag | title }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Provider Rating -->
|
||||
{% if product_data.product.metadata.rating %}
|
||||
<div class="mb-3">
|
||||
<div class="d-flex align-items-center">
|
||||
<span class="me-2">Rating:</span>
|
||||
{% if product_data.product.metadata.rating >= 1 %}<i class="bi bi-star-fill text-warning"></i>{% else %}<i class="bi bi-star text-muted"></i>{% endif %}
|
||||
{% if product_data.product.metadata.rating >= 2 %}<i class="bi bi-star-fill text-warning"></i>{% else %}<i class="bi bi-star text-muted"></i>{% endif %}
|
||||
{% if product_data.product.metadata.rating >= 3 %}<i class="bi bi-star-fill text-warning"></i>{% else %}<i class="bi bi-star text-muted"></i>{% endif %}
|
||||
{% if product_data.product.metadata.rating >= 4 %}<i class="bi bi-star-fill text-warning"></i>{% else %}<i class="bi bi-star text-muted"></i>{% endif %}
|
||||
{% if product_data.product.metadata.rating >= 5 %}<i class="bi bi-star-fill text-warning"></i>{% else %}<i class="bi bi-star text-muted"></i>{% endif %}
|
||||
<span class="ms-2 text-muted small">({{ product_data.product.metadata.review_count }} reviews)</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="price-info">
|
||||
<div class="fw-bold text-primary fs-5">{{ product_data.formatted_price }}</div>
|
||||
<small class="text-muted">per engagement</small>
|
||||
</div>
|
||||
<div class="btn-group-vertical w-100">
|
||||
<div class="btn-group mb-2">
|
||||
<button class="btn btn-success btn-sm buy-now-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}"
|
||||
data-category="services">
|
||||
<i class="bi bi-lightning-charge me-1"></i>Buy Now
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm add-to-cart-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus me-1"></i>Add to Cart
|
||||
</button>
|
||||
</div>
|
||||
<a href="/products/{{ product_data.product.id }}" class="btn btn-outline-primary btn-sm">View Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-people display-1 text-muted"></i>
|
||||
<h4 class="mt-3">No Services Available</h4>
|
||||
<p class="text-muted">Check back later for new professional services.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if pagination and pagination.total_pages > 1 %}
|
||||
<nav aria-label="Service pages" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<!-- Previous Page -->
|
||||
<li class="page-item {% if not pagination.has_previous %}disabled{% endif %}">
|
||||
{% if pagination.has_previous %}
|
||||
<a class="page-link" href="?page={{ pagination.previous_page }}">Previous</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Previous</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 1 -->
|
||||
<li class="page-item {% if pagination.current_page == 0 %}active{% endif %}">
|
||||
{% if pagination.current_page == 0 %}
|
||||
<span class="page-link">1</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=0">1</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 2 (if exists) -->
|
||||
{% if pagination.total_pages > 1 %}
|
||||
<li class="page-item {% if pagination.current_page == 1 %}active{% endif %}">
|
||||
{% if pagination.current_page == 1 %}
|
||||
<span class="page-link">2</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=1">2</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 3 (if exists) -->
|
||||
{% if pagination.total_pages > 2 %}
|
||||
<li class="page-item {% if pagination.current_page == 2 %}active{% endif %}">
|
||||
{% if pagination.current_page == 2 %}
|
||||
<span class="page-link">3</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=2">3</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 4 (if exists) -->
|
||||
{% if pagination.total_pages > 3 %}
|
||||
<li class="page-item {% if pagination.current_page == 3 %}active{% endif %}">
|
||||
{% if pagination.current_page == 3 %}
|
||||
<span class="page-link">4</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=3">4</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 5 (if exists) -->
|
||||
{% if pagination.total_pages > 4 %}
|
||||
<li class="page-item {% if pagination.current_page == 4 %}active{% endif %}">
|
||||
{% if pagination.current_page == 4 %}
|
||||
<span class="page-link">5</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=4">5</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Next Page -->
|
||||
<li class="page-item {% if not pagination.has_next %}disabled{% endif %}">
|
||||
{% if pagination.has_next %}
|
||||
<a class="page-link" href="?page={{ pagination.next_page }}">Next</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Next</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Results Info -->
|
||||
<div class="text-center text-muted mt-2">
|
||||
Showing page {{ pagination.current_page + 1 }} of {{ pagination.total_pages }}
|
||||
({{ pagination.total_count }} total services)
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Service Categories -->
|
||||
<div class="row mt-5">
|
||||
<div class="col-12">
|
||||
<h3 class="mb-4">Service Categories</h3>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-lightbulb fs-1 text-primary mb-3"></i>
|
||||
<h5>Consulting & Strategy</h5>
|
||||
<p class="small text-muted">Architecture planning, technology assessment, and strategic guidance for your decentralized infrastructure.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-tools fs-1 text-primary mb-3"></i>
|
||||
<h5>Deployment & Setup</h5>
|
||||
<p class="small text-muted">Professional deployment, configuration, and optimization of your ThreeFold infrastructure and applications.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-headset fs-1 text-primary mb-3"></i>
|
||||
<h5>Support & Maintenance</h5>
|
||||
<p class="small text-muted">Ongoing support, monitoring, updates, and maintenance to keep your systems running smoothly.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.service-detail {
|
||||
margin-bottom: 8px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.service-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.price-info {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- JSON hydration for services (CSP-safe) -->
|
||||
<script type="application/json" id="services-data">{}</script>
|
||||
<!-- External JS (CSP-compliant) -->
|
||||
<script src="/static/js/services.js"></script>
|
||||
{% endblock %}
|
||||
447
src/views/marketplace/slice_rental_form.html
Normal file
447
src/views/marketplace/slice_rental_form.html
Normal file
@@ -0,0 +1,447 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - Rent Slice{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<a href="/marketplace/compute" class="btn btn-outline-secondary me-3">
|
||||
<i class="bi bi-arrow-left"></i> Back to Compute Resources
|
||||
</a>
|
||||
<h1 class="mb-0">Rent Compute Slice</h1>
|
||||
</div>
|
||||
|
||||
{% if slice %}
|
||||
<div class="row">
|
||||
<!-- Slice Information -->
|
||||
<div class="col-lg-4 mb-4">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Slice Details</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<strong>Node:</strong> {{ slice.node_id }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>Farmer:</strong> {{ slice.farmer_email }}
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>Specifications:</strong>
|
||||
<ul class="list-unstyled mt-2">
|
||||
<li><i class="bi bi-cpu me-2"></i>{{ slice.cpu_cores }} CPU Cores</li>
|
||||
<li><i class="bi bi-memory me-2"></i>{{ slice.memory_gb }} GB RAM</li>
|
||||
<li><i class="bi bi-hdd me-2"></i>{{ slice.storage_gb }} GB Storage</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>Price:</strong> ${{ slice.price_per_hour }}/hour
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong>Available:</strong>
|
||||
<span class="badge bg-success">{{ slice.available_quantity }} slices</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Rental Configuration Form -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Deployment Configuration</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="sliceRentalForm" method="POST" action="/marketplace/slice/rent">
|
||||
<!-- Hidden fields -->
|
||||
<input type="hidden" name="farmer_email" value="{{ farmer_email }}">
|
||||
<input type="hidden" name="node_id" value="{{ node_id }}">
|
||||
<input type="hidden" name="combination_id" value="{{ combination_id }}">
|
||||
|
||||
<!-- Basic Configuration -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<label for="quantity" class="form-label">Quantity</label>
|
||||
<input type="number" class="form-control" id="quantity" name="quantity"
|
||||
min="1" max="{{ slice.available_quantity }}" value="1" required>
|
||||
<div class="form-text">Number of slices to rent</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="rental_duration_hours" class="form-label">Duration (Hours)</label>
|
||||
<select class="form-select" id="rental_duration_hours" name="rental_duration_hours" required>
|
||||
<option value="24">1 Day (24 hours)</option>
|
||||
<option value="168">1 Week (168 hours)</option>
|
||||
<option value="720" selected>1 Month (720 hours)</option>
|
||||
<option value="2160">3 Months (2160 hours)</option>
|
||||
<option value="4320">6 Months (4320 hours)</option>
|
||||
<option value="8760">1 Year (8760 hours)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Deployment Type Selection -->
|
||||
<div class="mb-4">
|
||||
<label class="form-label">Deployment Type</label>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="card deployment-option" data-deployment="vm">
|
||||
<div class="card-body text-center">
|
||||
<input type="radio" class="btn-check" name="deployment_type" id="vm_deployment" value="vm" checked>
|
||||
<label class="btn btn-outline-primary w-100" for="vm_deployment">
|
||||
<i class="bi bi-pc-display-horizontal display-6 d-block mb-2"></i>
|
||||
<h5>Virtual Machine</h5>
|
||||
<p class="text-muted small mb-0">Deploy a single VM with your chosen OS</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card deployment-option" data-deployment="kubernetes">
|
||||
<div class="card-body text-center">
|
||||
<input type="radio" class="btn-check" name="deployment_type" id="k8s_deployment" value="kubernetes">
|
||||
<label class="btn btn-outline-primary w-100" for="k8s_deployment">
|
||||
<i class="bi bi-diagram-3 display-6 d-block mb-2"></i>
|
||||
<h5>Kubernetes Cluster</h5>
|
||||
<p class="text-muted small mb-0">Deploy a K8s cluster with configurable nodes</p>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- VM Configuration -->
|
||||
<div id="vm_config" class="deployment-config">
|
||||
<h6 class="mb-3">VM Configuration</h6>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="vm_name" class="form-label">VM Name</label>
|
||||
<input type="text" class="form-control" id="vm_name" name="vm_name"
|
||||
placeholder="my-vm" pattern="[a-zA-Z0-9-]+" required>
|
||||
<div class="form-text">Alphanumeric characters and hyphens only</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="vm_os" class="form-label">Operating System</label>
|
||||
<select class="form-select" id="vm_os" name="vm_os">
|
||||
<option value="ubuntu" selected>Ubuntu 22.04 LTS</option>
|
||||
<option value="debian">Debian 12</option>
|
||||
<option value="centos">CentOS Stream 9</option>
|
||||
<option value="alpine">Alpine Linux</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="vm_ssh_key" class="form-label">SSH Public Key (Optional)</label>
|
||||
<textarea class="form-control" id="vm_ssh_key" name="vm_ssh_key" rows="3"
|
||||
placeholder="ssh-rsa AAAAB3NzaC1yc2E..."></textarea>
|
||||
<div class="form-text">Paste your SSH public key for secure access</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Kubernetes Configuration -->
|
||||
<div id="k8s_config" class="deployment-config" style="display: none;">
|
||||
<h6 class="mb-3">Kubernetes Configuration</h6>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="cluster_name" class="form-label">Cluster Name</label>
|
||||
<input type="text" class="form-control" id="cluster_name" name="cluster_name"
|
||||
placeholder="my-k8s-cluster" pattern="[a-zA-Z0-9-]+">
|
||||
<div class="form-text">Alphanumeric characters and hyphens only</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="k8s_version" class="form-label">Kubernetes Version</label>
|
||||
<select class="form-select" id="k8s_version" name="k8s_version">
|
||||
<option value="1.29" selected>1.29 (Recommended)</option>
|
||||
<option value="1.28">1.28</option>
|
||||
<option value="1.30">1.30 (Latest)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-4">
|
||||
<label for="k8s_masters" class="form-label">Master Nodes</label>
|
||||
<select class="form-select" id="k8s_masters" name="k8s_masters">
|
||||
<option value="1" selected>1 Master</option>
|
||||
<option value="3">3 Masters (HA)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="k8s_workers" class="form-label">Worker Nodes</label>
|
||||
<select class="form-select" id="k8s_workers" name="k8s_workers">
|
||||
<option value="1" selected>1 Worker</option>
|
||||
<option value="2">2 Workers</option>
|
||||
<option value="3">3 Workers</option>
|
||||
<option value="5">5 Workers</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="k8s_network_plugin" class="form-label">Network Plugin</label>
|
||||
<select class="form-select" id="k8s_network_plugin" name="k8s_network_plugin">
|
||||
<option value="flannel" selected>Flannel</option>
|
||||
<option value="calico">Calico</option>
|
||||
<option value="weave">Weave Net</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Additional Options -->
|
||||
<div class="mb-4">
|
||||
<h6 class="mb-3">Additional Options</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="auto_scaling" name="auto_scaling">
|
||||
<label class="form-check-label" for="auto_scaling">
|
||||
Auto Scaling
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="backup_enabled" name="backup_enabled">
|
||||
<label class="form-check-label" for="backup_enabled">
|
||||
Enable Backups
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="monitoring_enabled" name="monitoring_enabled" checked>
|
||||
<label class="form-check-label" for="monitoring_enabled">
|
||||
Enable Monitoring
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Cost Calculation -->
|
||||
<div class="card bg-light mb-4">
|
||||
<div class="card-body">
|
||||
<h6 class="mb-3">Cost Calculation</h6>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Base Price per Hour:</span>
|
||||
<span id="base_price">${{ slice.price_per_hour }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Quantity:</span>
|
||||
<span id="quantity_display">1</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Duration:</span>
|
||||
<span id="duration_display">720 hours</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>Subtotal:</span>
|
||||
<span id="subtotal">${{ slice.price_per_hour * 720 }}</span>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between">
|
||||
<span>K8s Multiplier:</span>
|
||||
<span id="k8s_multiplier">1x</span>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="d-flex justify-content-between fw-bold">
|
||||
<span>Total Cost:</span>
|
||||
<span id="total_cost">${{ slice.price_per_hour * 720 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary btn-lg" id="submitBtn">
|
||||
<i class="bi bi-rocket me-2"></i>Deploy Now
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-exclamation-triangle display-1 text-warning"></i>
|
||||
<h4 class="mt-3">Slice Not Found</h4>
|
||||
<p class="text-muted">The requested slice combination could not be found.</p>
|
||||
<a href="/marketplace/compute" class="btn btn-primary">Browse Available Slices</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Pass data to JavaScript -->
|
||||
<script type="application/json" id="slice-data">
|
||||
{
|
||||
"basePrice": {% if slice %}{{ slice.price_per_hour }}{% else %}0{% endif %},
|
||||
"availableQuantity": {% if slice %}{{ slice.available_quantity }}{% else %}1{% endif %}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const vmRadio = document.getElementById('vm_deployment');
|
||||
const k8sRadio = document.getElementById('k8s_deployment');
|
||||
const vmConfig = document.getElementById('vm_config');
|
||||
const k8sConfig = document.getElementById('k8s_config');
|
||||
const form = document.getElementById('sliceRentalForm');
|
||||
|
||||
// Get data from JSON script tag
|
||||
const sliceData = JSON.parse(document.getElementById('slice-data').textContent);
|
||||
const basePrice = sliceData.basePrice;
|
||||
|
||||
// Toggle deployment configuration
|
||||
function toggleDeploymentConfig() {
|
||||
if (vmRadio.checked) {
|
||||
vmConfig.style.display = 'block';
|
||||
k8sConfig.style.display = 'none';
|
||||
// Make VM fields required
|
||||
document.getElementById('vm_name').required = true;
|
||||
document.getElementById('cluster_name').required = false;
|
||||
} else {
|
||||
vmConfig.style.display = 'none';
|
||||
k8sConfig.style.display = 'block';
|
||||
// Make K8s fields required
|
||||
document.getElementById('vm_name').required = false;
|
||||
document.getElementById('cluster_name').required = true;
|
||||
}
|
||||
updateCostCalculation();
|
||||
}
|
||||
|
||||
// Update cost calculation
|
||||
function updateCostCalculation() {
|
||||
const quantity = parseInt(document.getElementById('quantity').value) || 1;
|
||||
const duration = parseInt(document.getElementById('rental_duration_hours').value) || 720;
|
||||
const masters = parseInt(document.getElementById('k8s_masters').value) || 1;
|
||||
const workers = parseInt(document.getElementById('k8s_workers').value) || 1;
|
||||
|
||||
let multiplier = 1;
|
||||
if (k8sRadio.checked) {
|
||||
multiplier = masters + workers;
|
||||
}
|
||||
|
||||
const subtotal = basePrice * quantity * duration;
|
||||
const total = subtotal * multiplier;
|
||||
|
||||
document.getElementById('quantity_display').textContent = quantity;
|
||||
document.getElementById('duration_display').textContent = duration + ' hours';
|
||||
document.getElementById('subtotal').textContent = '$' + subtotal.toFixed(2);
|
||||
document.getElementById('k8s_multiplier').textContent = multiplier + 'x';
|
||||
document.getElementById('total_cost').textContent = '$' + total.toFixed(2);
|
||||
}
|
||||
|
||||
// Event listeners
|
||||
vmRadio.addEventListener('change', toggleDeploymentConfig);
|
||||
k8sRadio.addEventListener('change', toggleDeploymentConfig);
|
||||
document.getElementById('quantity').addEventListener('input', updateCostCalculation);
|
||||
document.getElementById('rental_duration_hours').addEventListener('change', updateCostCalculation);
|
||||
document.getElementById('k8s_masters').addEventListener('change', updateCostCalculation);
|
||||
document.getElementById('k8s_workers').addEventListener('change', updateCostCalculation);
|
||||
|
||||
// Form submission
|
||||
form.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
const originalText = submitBtn.innerHTML;
|
||||
submitBtn.innerHTML = '<i class="bi bi-hourglass-split me-2"></i>Deploying...';
|
||||
submitBtn.disabled = true;
|
||||
|
||||
const formData = new FormData(form);
|
||||
|
||||
window.apiJson('/marketplace/slice/rent', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response)
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
// Show success message
|
||||
const alertDiv = document.createElement('div');
|
||||
alertDiv.className = 'alert alert-success alert-dismissible fade show';
|
||||
alertDiv.innerHTML = `
|
||||
<i class="bi bi-check-circle me-2"></i>
|
||||
${data.message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
form.parentNode.insertBefore(alertDiv, form);
|
||||
|
||||
// Redirect after 3 seconds
|
||||
setTimeout(() => {
|
||||
if (data.redirect_url) {
|
||||
window.location.href = data.redirect_url;
|
||||
}
|
||||
}, 3000);
|
||||
} else {
|
||||
// Show error message
|
||||
const alertDiv = document.createElement('div');
|
||||
alertDiv.className = 'alert alert-danger alert-dismissible fade show';
|
||||
alertDiv.innerHTML = `
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
${data.message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
form.parentNode.insertBefore(alertDiv, form);
|
||||
|
||||
submitBtn.innerHTML = originalText;
|
||||
submitBtn.disabled = false;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
const alertDiv = document.createElement('div');
|
||||
alertDiv.className = 'alert alert-danger alert-dismissible fade show';
|
||||
alertDiv.innerHTML = `
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
An error occurred while processing your request.
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
form.parentNode.insertBefore(alertDiv, form);
|
||||
|
||||
submitBtn.innerHTML = originalText;
|
||||
submitBtn.disabled = false;
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize
|
||||
toggleDeploymentConfig();
|
||||
updateCostCalculation();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.deployment-option {
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.deployment-option:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.deployment-config {
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.375rem;
|
||||
padding: 1rem;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.btn-check:checked + .btn {
|
||||
background-color: var(--bs-primary);
|
||||
border-color: var(--bs-primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.spec-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
249
src/views/marketplace/statistics.html
Normal file
249
src/views/marketplace/statistics.html
Normal file
@@ -0,0 +1,249 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - Statistics{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<h1>Marketplace Statistics</h1>
|
||||
<p class="lead">Analytics and utilization statistics for the Project Mycelium</p>
|
||||
|
||||
<!-- Overview Stats -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Resource Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="resourceDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Monthly Growth</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="monthlyGrowthChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compute Resources Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Compute Resources Statistics</h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>CPU Utilization by Region</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="cpuUtilizationChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Memory Allocation</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="memoryAllocationChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Storage Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="storageDistributionChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Resource Pricing Trends</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="resourcePricingChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3Nodes Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>3Nodes Statistics</h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Geographic Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="nodeGeographicChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Node Types Distribution</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="nodeTypesChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Uptime Performance</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="nodeUptimeChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>3Node Certification Rate</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="nodeCertificationChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gateways Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Gateways Statistics</h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Gateway Traffic</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="gatewayTrafficChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Gateway Availability</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="gatewayAvailabilityChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Applications Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Applications Statistics</h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Application Categories</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="appCategoriesChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Deployment Trends</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="appDeploymentChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Services Section -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<div class="dashboard-section">
|
||||
<h3>Services Statistics</h3>
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Service Categories</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="serviceCategoriesChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="card mb-4 h-100">
|
||||
<div class="card-header">
|
||||
<h5>Average Hourly Rates</h5>
|
||||
</div>
|
||||
<div class="card-body d-flex justify-content-center align-items-center">
|
||||
<canvas id="serviceRatesChart" width="400" height="300"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
|
||||
<style>
|
||||
/* Ensure charts have consistent sizes */
|
||||
.card.h-100 {
|
||||
height: 400px !important;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
height: 340px;
|
||||
}
|
||||
</style>
|
||||
<script type="application/json" id="statistics-data">
|
||||
{
|
||||
}
|
||||
</script>
|
||||
<script src="/static/js/statistics.js"></script>
|
||||
{% endblock %}
|
||||
383
src/views/marketplace/three_nodes.html
Normal file
383
src/views/marketplace/three_nodes.html
Normal file
@@ -0,0 +1,383 @@
|
||||
{% extends "marketplace/layout.html" %}
|
||||
|
||||
{% block title %}Project Mycelium - 3Nodes Hardware{% endblock %}
|
||||
|
||||
{% block marketplace_content %}
|
||||
<div class="my-4">
|
||||
<h1>3Nodes Hardware</h1>
|
||||
<p class="lead">Discover certified hardware nodes that power the ThreeFold Grid infrastructure.</p>
|
||||
|
||||
<!-- 3Nodes Introduction -->
|
||||
<div class="alert alert-info mb-4">
|
||||
<div class="d-flex">
|
||||
<div class="me-3">
|
||||
<i class="bi bi-server fs-3"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h5 class="alert-heading">What are 3Nodes?</h5>
|
||||
<p>3Nodes are the physical hardware units that make up the ThreeFold Grid. These certified servers provide compute, storage, and network capacity to the decentralized internet infrastructure.</p>
|
||||
<hr>
|
||||
<p class="mb-0">By purchasing a 3Node, you become a farmer in the ThreeFold ecosystem, earning TFT rewards while contributing to the decentralized internet.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter and Search Section -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Filter 3Nodes</h5>
|
||||
<form class="row g-3" method="GET">
|
||||
<div class="col-md-3">
|
||||
<label for="locationFilter" class="form-label">Location</label>
|
||||
<select name="location" id="locationFilter" class="form-select">
|
||||
<option value="">All Locations</option>
|
||||
<option value="Belgium">Belgium</option>
|
||||
<option value="Austria">Austria</option>
|
||||
<option value="Switzerland">Switzerland</option>
|
||||
<option value="Netherlands">Netherlands</option>
|
||||
<option value="Germany">Germany</option>
|
||||
<option value="France">France</option>
|
||||
<option value="UK">UK</option>
|
||||
<option value="Canada">Canada</option>
|
||||
<option value="USA">USA</option>
|
||||
<option value="Japan">Japan</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="certificationFilter" class="form-label">Certification</label>
|
||||
<select name="certification_status" id="certificationFilter" class="form-select">
|
||||
<option value="">All Types</option>
|
||||
<option value="DIY">DIY Nodes</option>
|
||||
<option value="Certified">Certified Nodes</option>
|
||||
<option value="Titan">Titan Nodes</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="minPriceFilter" class="form-label">Min Price ($)</label>
|
||||
<input type="number" name="min_price" id="minPriceFilter" class="form-control"
|
||||
value="" placeholder="0" min="0" step="10">
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label for="maxPriceFilter" class="form-label">Max Price ($)</label>
|
||||
<input type="number" name="max_price" id="maxPriceFilter" class="form-control"
|
||||
value="" placeholder="500" min="0" step="10">
|
||||
</div>
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<button type="submit" class="btn btn-primary me-2">Apply Filters</button>
|
||||
<a href="/marketplace/3nodes" class="btn btn-outline-secondary">Clear</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3Nodes Grid -->
|
||||
<div class="row">
|
||||
{% if hardware_products and hardware_products | length > 0 %}
|
||||
{% for product_data in hardware_products %}
|
||||
<div class="col-lg-6 mb-4">
|
||||
<div class="card h-100">
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-start mb-3">
|
||||
<div class="node-icon me-3">
|
||||
<i class="bi bi-server fs-2 text-primary"></i>
|
||||
</div>
|
||||
<div class="flex-grow-1">
|
||||
<div class="d-flex justify-content-between align-items-start">
|
||||
<h5 class="card-title mb-1">
|
||||
<a href="/products/{{ product_data.product.id }}" class="text-decoration-none text-dark">
|
||||
{{ product_data.product.name }}
|
||||
</a>
|
||||
</h5>
|
||||
{% if product_data.product.metadata.featured %}
|
||||
<span class="badge bg-warning">Featured</span>
|
||||
{% elif product_data.product.availability == "Available" %}
|
||||
<span class="badge bg-success">Available</span>
|
||||
{% else %}
|
||||
<span class="badge bg-secondary">{{ product_data.product.availability }}</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="text-muted small mb-2">
|
||||
<i class="bi bi-building me-1"></i>{{ product_data.product.provider_name }}
|
||||
{% if product_data.product.metadata.location %}
|
||||
<span class="ms-2">
|
||||
<i class="bi bi-geo-alt me-1"></i>{{ product_data.product.metadata.location }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="card-text">{{ product_data.product.description | truncate(length=120) }}</p>
|
||||
|
||||
<!-- Hardware Specifications -->
|
||||
{% if product_data.product.attributes %}
|
||||
<div class="mb-3">
|
||||
<h6 class="mb-2">Hardware Specifications:</h6>
|
||||
<div class="row">
|
||||
{% if product_data.product.attributes.cpu_cores %}
|
||||
<div class="col-md-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-cpu me-2 text-primary"></i>
|
||||
<span>{{ product_data.product.attributes.cpu_cores.value }} CPU Cores</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.memory_gb %}
|
||||
<div class="col-md-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-memory me-2 text-primary"></i>
|
||||
<span>{{ product_data.product.attributes.memory_gb.value }} GB RAM</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.storage_gb %}
|
||||
<div class="col-md-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-hdd me-2 text-primary"></i>
|
||||
<span>{{ product_data.product.attributes.storage_gb.value }} GB Storage</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if product_data.product.attributes.bandwidth_mbps %}
|
||||
<div class="col-md-6">
|
||||
<div class="spec-item">
|
||||
<i class="bi bi-speedometer2 me-2 text-primary"></i>
|
||||
<span>{{ product_data.product.attributes.bandwidth_mbps.value }} Mbps Network</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Node Features -->
|
||||
{% if product_data.product.metadata.tags and product_data.product.metadata.tags | length > 0 %}
|
||||
<div class="mb-3">
|
||||
<h6 class="mb-2">Features:</h6>
|
||||
<div class="d-flex flex-wrap">
|
||||
{% for tag in product_data.product.metadata.tags %}
|
||||
<span class="badge bg-light text-dark me-1 mb-1">{{ tag | title }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Farming Potential -->
|
||||
<div class="mb-3">
|
||||
<div class="alert alert-success small">
|
||||
<i class="bi bi-currency-dollar me-1"></i>
|
||||
<strong>Farming Potential:</strong> Earn TFT rewards by contributing to the ThreeFold Grid
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer bg-transparent">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div class="price-info">
|
||||
<div class="fw-bold text-primary fs-5">{{ product_data.formatted_price }}</div>
|
||||
<small class="text-muted">one-time purchase</small>
|
||||
</div>
|
||||
<div class="btn-group-vertical w-100">
|
||||
<div class="btn-group mb-2">
|
||||
<button class="btn btn-success btn-sm buy-now-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}"
|
||||
data-category="3nodes">
|
||||
<i class="bi bi-lightning-charge me-1"></i>Buy Now
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm add-to-cart-btn"
|
||||
data-product-id="{{ product_data.product.id }}"
|
||||
data-product-name="{{ product_data.product.name }}"
|
||||
data-unit-price="{{ product_data.price.display_amount }}"
|
||||
data-currency="{{ product_data.price.display_currency }}">
|
||||
<i class="bi bi-cart-plus me-1"></i>Add to Cart
|
||||
</button>
|
||||
</div>
|
||||
<a href="/products/{{ product_data.product.id }}" class="btn btn-outline-primary btn-sm">View Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="col-12">
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-server display-1 text-muted"></i>
|
||||
<h4 class="mt-3">No 3Nodes Available</h4>
|
||||
<p class="text-muted">Check back later for new hardware offerings.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if pagination and pagination.total_pages > 1 %}
|
||||
<nav aria-label="3Node pages" class="mt-4">
|
||||
<ul class="pagination justify-content-center">
|
||||
<!-- Previous Page -->
|
||||
<li class="page-item {% if not pagination.has_previous %}disabled{% endif %}">
|
||||
{% if pagination.has_previous %}
|
||||
<a class="page-link" href="?page={{ pagination.previous_page }}">Previous</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Previous</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 1 -->
|
||||
<li class="page-item {% if pagination.current_page == 0 %}active{% endif %}">
|
||||
{% if pagination.current_page == 0 %}
|
||||
<span class="page-link">1</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=0">1</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
|
||||
<!-- Page 2 (if exists) -->
|
||||
{% if pagination.total_pages > 1 %}
|
||||
<li class="page-item {% if pagination.current_page == 1 %}active{% endif %}">
|
||||
{% if pagination.current_page == 1 %}
|
||||
<span class="page-link">2</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=1">2</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 3 (if exists) -->
|
||||
{% if pagination.total_pages > 2 %}
|
||||
<li class="page-item {% if pagination.current_page == 2 %}active{% endif %}">
|
||||
{% if pagination.current_page == 2 %}
|
||||
<span class="page-link">3</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=2">3</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 4 (if exists) -->
|
||||
{% if pagination.total_pages > 3 %}
|
||||
<li class="page-item {% if pagination.current_page == 3 %}active{% endif %}">
|
||||
{% if pagination.current_page == 3 %}
|
||||
<span class="page-link">4</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=3">4</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Page 5 (if exists) -->
|
||||
{% if pagination.total_pages > 4 %}
|
||||
<li class="page-item {% if pagination.current_page == 4 %}active{% endif %}">
|
||||
{% if pagination.current_page == 4 %}
|
||||
<span class="page-link">5</span>
|
||||
{% else %}
|
||||
<a class="page-link" href="?page=4">5</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
<!-- Next Page -->
|
||||
<li class="page-item {% if not pagination.has_next %}disabled{% endif %}">
|
||||
{% if pagination.has_next %}
|
||||
<a class="page-link" href="?page={{ pagination.next_page }}">Next</a>
|
||||
{% else %}
|
||||
<span class="page-link" tabindex="-1" aria-disabled="true">Next</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- Results Info -->
|
||||
<div class="text-center text-muted mt-2">
|
||||
Showing page {{ pagination.current_page + 1 }} of {{ pagination.total_pages }}
|
||||
({{ pagination.total_count }} total 3Nodes)
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Farming Information -->
|
||||
<div class="row mt-5">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Become a ThreeFold Farmer</h3>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h5>1. Purchase Your 3Node</h5>
|
||||
<p>Choose from certified hardware options that meet ThreeFold Grid requirements.</p>
|
||||
|
||||
<h5>2. Connect to the Grid</h5>
|
||||
<p>Boot your 3Node with Zero-OS and connect it to the ThreeFold Grid infrastructure.</p>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<h5>3. Start Earning</h5>
|
||||
<p>Your 3Node automatically provides capacity to the grid and earns TFT rewards based on utilization.</p>
|
||||
|
||||
<h5>4. Monitor & Maintain</h5>
|
||||
<p>Use the ThreeFold Dashboard to monitor your node's performance and earnings.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info mt-3">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>ROI Potential:</strong> 3Node farmers typically see return on investment within 2-4 years, depending on grid utilization and TFT price.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Node Types -->
|
||||
<div class="row mt-4">
|
||||
<div class="col-12">
|
||||
<h3 class="mb-4">3Node Types</h3>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-tools fs-1 text-primary mb-3"></i>
|
||||
<h5>DIY Nodes</h5>
|
||||
<p class="small text-muted">Build your own 3Node using compatible hardware. Most cost-effective option for technical users.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-award fs-1 text-primary mb-3"></i>
|
||||
<h5>Certified Nodes</h5>
|
||||
<p class="small text-muted">Pre-built and certified hardware that's guaranteed to work with the ThreeFold Grid.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<i class="bi bi-lightning fs-1 text-primary mb-3"></i>
|
||||
<h5>Titan Nodes</h5>
|
||||
<p class="small text-muted">High-performance enterprise-grade nodes for maximum farming potential and grid contribution.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.spec-item {
|
||||
margin-bottom: 8px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.node-icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.price-info {
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script src="/static/js/marketplace-category.js"></script>
|
||||
{% endblock %}
|
||||
384
src/views/roadmap.html
Normal file
384
src/views/roadmap.html
Normal file
@@ -0,0 +1,384 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Roadmap - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container my-5">
|
||||
<div class="row">
|
||||
<div class="col-lg-10 mx-auto">
|
||||
<div class="d-flex align-items-center mb-4">
|
||||
<i class="bi bi-map me-3" style="font-size: 2rem; color: #0066cc;"></i>
|
||||
<div>
|
||||
<h1 class="mb-1">Project Mycelium Roadmap</h1>
|
||||
<p class="text-muted mb-0">Development phases and strategic vision for the complete marketplace ecosystem</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current Progress Overview -->
|
||||
<div class="alert alert-info mb-5">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-8">
|
||||
<h5 class="alert-heading mb-2">
|
||||
<i class="bi bi-graph-up me-2"></i>Current Progress: Phase 2 - Architecture Refactor
|
||||
</h5>
|
||||
<p class="mb-0">Architecture Refactor Program: <strong>85% overall</strong> — ResponseBuilder migration: <strong>100%</strong></p>
|
||||
<p class="mb-0 mt-1"><span class="badge bg-secondary me-2">Latest release</span> v0.0.6 — 2025-08-18</p>
|
||||
</div>
|
||||
<div class="col-md-4 text-end">
|
||||
<div class="progress" style="height: 20px;">
|
||||
<div class="progress-bar bg-success" role="progressbar" style="width: 85%" aria-valuenow="85" aria-valuemin="0" aria-valuemax="100">85%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="roadmap-content">
|
||||
<!-- Phase 1: Foundation (Complete) -->
|
||||
<div class="roadmap-phase mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-success me-3 px-3 py-2">Phase 1</span>
|
||||
<h2 class="h3 mb-0">Foundation & Core Platform</h2>
|
||||
<span class="badge bg-success ms-auto">COMPLETE</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group completed">
|
||||
<h4 class="h5 text-success mb-3">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>TFC Credits System
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Single currency model (1 TFC = 1 USD)</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Complete TFP → TFC migration</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Simplified pricing structure</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Industry-standard credit model</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group completed">
|
||||
<h4 class="h5 text-success mb-3">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>Platform Foundation
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Core marketplace functionality</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>User authentication & dashboard</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Cart & checkout system</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>ThreeFold Grid integration</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phase 2: Architecture Refactor (In Progress) -->
|
||||
<div class="roadmap-phase mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-primary me-3 px-3 py-2">Phase 2</span>
|
||||
<h2 class="h3 mb-0">Architecture Refactor & Code Quality</h2>
|
||||
<span class="badge bg-primary ms-auto">IN PROGRESS</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group in-progress">
|
||||
<h4 class="h5 text-primary mb-3">
|
||||
<i class="bi bi-gear-fill me-2"></i>Builder Pattern Migration
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>ResponseBuilder architecture implemented</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>SessionDataBuilder for user persistence</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>All controllers migrated to ResponseBuilder</li>
|
||||
<li class="mb-2"><i class="bi bi-clock text-warning me-2"></i>Program progress: <strong>85%</strong> — remaining: DataAggregator, mock sweep, dashboard persistence, SLA list, cart flow, status normalization</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group in-progress">
|
||||
<h4 class="h5 text-primary mb-3">
|
||||
<i class="bi bi-shield-check me-2"></i>Code Quality Improvements
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>881+ log statements removed</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>Zero compilation errors maintained</li>
|
||||
<li class="mb-2"><i class="bi bi-check-circle-fill text-success me-2"></i>1,120+ lines of code reduced</li>
|
||||
<li class="mb-2"><i class="bi bi-clock text-warning me-2"></i>Ongoing audits and cleanup</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Current Sprint Details -->
|
||||
<div class="alert alert-light border-primary">
|
||||
<h5 class="text-primary mb-3">
|
||||
<i class="bi bi-calendar-week me-2"></i>Current Sprint Focus
|
||||
</h5>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<strong>Immediate (This Week)</strong>
|
||||
<ul class="mt-2">
|
||||
<li>Centralized insufficient-funds handling (HTTP 402): global interceptor + client audits implemented; verification of niche pages pending</li>
|
||||
<li>Service Requests & Bookings sync — backend atomic updates, frontend row migration, tests</li>
|
||||
<li>Mock gating & removal sweep — gate with APP_ENABLE_MOCKS and remove mocks</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<strong>Short Term (2-4 weeks)</strong>
|
||||
<ul class="mt-2">
|
||||
<li>Dashboard persistent-only completion</li>
|
||||
<li>Cart flow fixes — no pre-check funds on add-to-cart; enforce at checkout/buy-now</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<strong>Medium Term (1-2 months)</strong>
|
||||
<ul class="mt-2">
|
||||
<li>Dashboard Controller completion</li>
|
||||
<li>Final architecture validation</li>
|
||||
<li>Performance optimization</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phase 3: Complete Marketplace Ecosystem -->
|
||||
<div class="roadmap-phase mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-warning me-3 px-3 py-2">Phase 3</span>
|
||||
<h2 class="h3 mb-0">Complete Marketplace Ecosystem</h2>
|
||||
<span class="badge bg-outline-secondary ms-auto">PLANNED</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group planned">
|
||||
<h4 class="h5 text-warning mb-3">
|
||||
<i class="bi bi-credit-card me-2"></i>Payment Integration
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Stripe integration for TFC purchases</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>TFC → TFT conversion service</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Commission calculation system</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Automated payment processing</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group planned">
|
||||
<h4 class="h5 text-warning mb-3">
|
||||
<i class="bi bi-cloud-arrow-up me-2"></i>Deployment Automation
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Automated ThreeFold Grid deployment</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Real-time deployment status</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Resource provisioning pipeline</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Deployment queue management</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group planned">
|
||||
<h4 class="h5 text-warning mb-3">
|
||||
<i class="bi bi-database me-2"></i>Database Evolution
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>PostgreSQL schema design</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>JSON to SQL migration</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Supabase deployment</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Data consistency validation</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group planned">
|
||||
<h4 class="h5 text-warning mb-3">
|
||||
<i class="bi bi-people me-2"></i>Enhanced User Experience
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Web2/Web3 bridge UX</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Seamless fiat to crypto flow</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Advanced marketplace features</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Mobile-responsive design</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Phase 4: High Availability & Scale -->
|
||||
<div class="roadmap-phase mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-info me-3 px-3 py-2">Phase 4</span>
|
||||
<h2 class="h3 mb-0">High Availability & Enterprise Scale</h2>
|
||||
<span class="badge bg-outline-secondary ms-auto">FUTURE</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group future">
|
||||
<h4 class="h5 text-info mb-3">
|
||||
<i class="bi bi-diagram-3 me-2"></i>Infrastructure Scaling
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>k3s cluster deployment</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Multi-node redundancy</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Horizontal scaling capabilities</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Load balancing & failover</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="feature-group future">
|
||||
<h4 class="h5 text-info mb-3">
|
||||
<i class="bi bi-graph-up-arrow me-2"></i>Advanced Features
|
||||
</h4>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>AI-powered resource optimization</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Advanced analytics & reporting</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Multi-tenant architecture</li>
|
||||
<li class="mb-2"><i class="bi bi-circle text-muted me-2"></i>Enterprise API gateway</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Technical Architecture Vision -->
|
||||
<div class="roadmap-phase mb-5">
|
||||
<div class="d-flex align-items-center mb-3">
|
||||
<span class="badge bg-dark me-3 px-3 py-2">Vision</span>
|
||||
<h2 class="h3 mb-0">Complete Technical Architecture</h2>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-dark">
|
||||
<h5 class="mb-3">
|
||||
<i class="bi bi-diagram-2 me-2"></i>End-to-End User Journey
|
||||
</h5>
|
||||
<div class="row">
|
||||
<div class="col-md-3 text-center mb-3">
|
||||
<div class="border rounded p-3 bg-light">
|
||||
<i class="bi bi-person-circle display-6 text-primary"></i>
|
||||
<h6 class="mt-2">User Discovery</h6>
|
||||
<small class="text-muted">Browse marketplace, select services</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-center mb-3">
|
||||
<div class="border rounded p-3 bg-light">
|
||||
<i class="bi bi-credit-card display-6 text-success"></i>
|
||||
<h6 class="mt-2">Payment</h6>
|
||||
<small class="text-muted">Stripe → TFC → TFT conversion</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-center mb-3">
|
||||
<div class="border rounded p-3 bg-light">
|
||||
<i class="bi bi-cloud-arrow-up display-6 text-warning"></i>
|
||||
<h6 class="mt-2">Deployment</h6>
|
||||
<small class="text-muted">Automated Grid provisioning</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3 text-center mb-3">
|
||||
<div class="border rounded p-3 bg-light">
|
||||
<i class="bi bi-check-circle display-6 text-info"></i>
|
||||
<h6 class="mt-2">Management</h6>
|
||||
<small class="text-muted">Real-time monitoring & control</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-5 pt-4 border-top">
|
||||
<p class="text-muted">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
For detailed technical specifications, see our
|
||||
<a href="/docs" class="text-decoration-none">architecture documentation</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.roadmap-phase {
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 12px;
|
||||
padding: 2rem;
|
||||
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.roadmap-phase:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.feature-group {
|
||||
background: rgba(255,255,255,0.7);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
height: 100%;
|
||||
border: 1px solid rgba(0,102,204,0.1);
|
||||
}
|
||||
|
||||
.feature-group.completed {
|
||||
border-color: rgba(40, 167, 69, 0.3);
|
||||
background: rgba(40, 167, 69, 0.05);
|
||||
}
|
||||
|
||||
.feature-group.in-progress {
|
||||
border-color: rgba(0, 123, 255, 0.3);
|
||||
background: rgba(0, 123, 255, 0.05);
|
||||
}
|
||||
|
||||
.feature-group.planned {
|
||||
border-color: rgba(255, 193, 7, 0.3);
|
||||
background: rgba(255, 193, 7, 0.05);
|
||||
}
|
||||
|
||||
.feature-group.future {
|
||||
border-color: rgba(23, 162, 184, 0.3);
|
||||
background: rgba(23, 162, 184, 0.05);
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.roadmap-content .bi-check-circle-fill {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.roadmap-content .bi-clock {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.roadmap-content .bi-circle {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.roadmap-content h4 {
|
||||
border-bottom: 2px solid rgba(0,102,204,0.2);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.progress {
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
347
src/views/wallet/index.html
Normal file
347
src/views/wallet/index.html
Normal file
@@ -0,0 +1,347 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Wallet - Project Mycelium{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<!-- Sidebar -->
|
||||
<div class="col-md-3 col-lg-2 d-md-block bg-light sidebar">
|
||||
<div class="position-sticky pt-3">
|
||||
<ul class="nav flex-column">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/dashboard">
|
||||
<i class="fas fa-tachometer-alt"></i> Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="/wallet">
|
||||
<i class="fas fa-wallet"></i> Wallet
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/marketplace">
|
||||
<i class="fas fa-store"></i> Marketplace
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main content -->
|
||||
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">USD Credits Wallet</h1>
|
||||
</div>
|
||||
|
||||
<!-- Wallet Balance Card -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card bg-primary text-white">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">
|
||||
<i class="fas fa-coins"></i> Current Balance
|
||||
</h5>
|
||||
<h2 class="card-text" id="wallet-balance">
|
||||
{% if wallet_balance %}
|
||||
${{ wallet_balance | format_decimal(precision=2) }}
|
||||
{% else %}
|
||||
$0.00
|
||||
{% endif %}
|
||||
</h2>
|
||||
<small class="text-light">USD Credits</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Top-Up Section (OpenRouter-style) -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card border-success">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-bolt"></i> Quick Top-Up
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-3">Add credits to your wallet instantly</p>
|
||||
|
||||
<!-- Currency Selection -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-6">
|
||||
<label for="topupCurrency" class="form-label">Currency</label>
|
||||
<select class="form-select" id="topupCurrency">
|
||||
<option value="USD" selected>USD ($)</option>
|
||||
<option value="EUR">EUR (€)</option>
|
||||
<option value="USD">USD</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label for="customAmount" class="form-label">Custom Amount</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text" id="currencySymbol">$</span>
|
||||
<input type="number" class="form-control" id="customAmount" placeholder="Enter amount" min="1" step="0.01">
|
||||
<button class="btn btn-outline-primary" type="button" id="customAmountAddBtn">
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Amount Buttons -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<label class="form-label">Quick Amounts</label>
|
||||
<div class="d-flex flex-wrap gap-2" id="quickAmountButtons">
|
||||
<button class="btn btn-outline-success" data-amount="10">$10</button>
|
||||
<button class="btn btn-outline-success" data-amount="25">$25</button>
|
||||
<button class="btn btn-outline-success" data-amount="50">$50</button>
|
||||
<button class="btn btn-outline-success" data-amount="100">$100</button>
|
||||
</div>
|
||||
<small class="text-muted d-block mt-2" id="conversionNote">
|
||||
Direct USD credits purchase
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Wallet Actions</h5>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#buyCreditsModal">
|
||||
<i class="fas fa-plus"></i> Buy Credits
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#transferCreditsModal">
|
||||
<i class="fas fa-paper-plane"></i> Transfer Credits
|
||||
</button>
|
||||
<button type="button" class="btn btn-info" id="refreshWalletBtn">
|
||||
<i class="fas fa-sync-alt"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Auto Top-up Configuration -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-12">
|
||||
<div class="card border-info">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-magic"></i> Auto Top-up (OpenRouter Style)
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-muted mb-3">Automatically purchase credits when your balance gets low</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="autoTopupEnabled">
|
||||
<label class="form-check-label" for="autoTopupEnabled">
|
||||
Enable Auto Top-up
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="thresholdAmount" class="form-label">When credits are below:</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="thresholdAmount" value="10" min="1" step="1">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="topupAmount" class="form-label">Purchase this amount:</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="topupAmount" value="25" min="5" step="5">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="paymentMethod" class="form-label">Payment Method:</label>
|
||||
<select class="form-select" id="autoTopupPaymentMethod">
|
||||
<option value="credit_card">Credit Card ****1234</option>
|
||||
<option value="paypal">PayPal</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="dailyLimit" class="form-label">Daily Limit (Optional):</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text">$</span>
|
||||
<input type="number" class="form-control" id="dailyLimit" placeholder="100" min="10" step="10">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-info" id="saveAutoTopupBtn">
|
||||
<i class="fas fa-save"></i> Save Auto Top-up Settings
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Recent Transactions -->
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">
|
||||
<i class="fas fa-history"></i> Recent Transactions
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped" id="transactions-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Type</th>
|
||||
<th>Amount</th>
|
||||
<th>Status</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="transactions-tbody">
|
||||
{% if transaction_history %}
|
||||
{% for transaction in transaction_history %}
|
||||
<tr>
|
||||
<td>{{ transaction.formatted_timestamp }}</td>
|
||||
<td>
|
||||
{% if transaction.transaction_type.CreditsPurchase %}
|
||||
<span class="badge bg-success">Purchase</span>
|
||||
{% elif transaction.transaction_type.Rental %}
|
||||
<span class="badge bg-primary">Rental</span>
|
||||
{% elif transaction.transaction_type.Purchase %}
|
||||
<span class="badge bg-warning">Buy</span>
|
||||
{% elif transaction.transaction_type.Transfer %}
|
||||
<span class="badge bg-info">Transfer</span>
|
||||
{% elif transaction.transaction_type.Earning %}
|
||||
<span class="badge bg-success">Earning</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if transaction.transaction_type.CreditsPurchase or transaction.transaction_type.Earning %}
|
||||
<span class="text-success">+${{ transaction.amount }}</span>
|
||||
{% else %}
|
||||
<span class="text-danger">-${{ transaction.amount }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if transaction.status == "Completed" %}
|
||||
<span class="badge bg-success">{{ transaction.status }}</span>
|
||||
{% elif transaction.status == "Pending" %}
|
||||
<span class="badge bg-warning">{{ transaction.status }}</span>
|
||||
{% else %}
|
||||
<span class="badge bg-danger">{{ transaction.status }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ transaction.id }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Buy Credits Modal -->
|
||||
<div class="modal fade" id="buyCreditsModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Buy USD Credits</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="buyCreditsForm">
|
||||
<div class="mb-3">
|
||||
<label for="creditsAmount" class="form-label">Amount (USD)</label>
|
||||
<input type="number" class="form-control" id="creditsAmount" min="1" max="10000" step="0.01" required>
|
||||
<div class="form-text">Minimum: $1, Maximum: $10,000</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="paymentMethod" class="form-label">Payment Method</label>
|
||||
<select class="form-select" id="buyPaymentMethod" required>
|
||||
<option value="">Select payment method</option>
|
||||
<option value="credit_card">Credit Card</option>
|
||||
<option value="paypal">PayPal</option>
|
||||
<option value="bank_transfer">Bank Transfer</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="alert alert-info">
|
||||
<strong>Exchange Rate:</strong> 1 Credit = $1.00<br>
|
||||
<strong>Total Cost:</strong> $<span id="totalCost">0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="buyCreditsBtn">Purchase Credits</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Transfer Credits Modal -->
|
||||
<div class="modal fade" id="transferCreditsModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Transfer Credits</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="transferCreditsForm">
|
||||
<div class="mb-3">
|
||||
<label for="recipientEmail" class="form-label">Recipient Email</label>
|
||||
<input type="email" class="form-control" id="recipientEmail" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="transferAmount" class="form-label">Amount (USD)</label>
|
||||
<input type="number" class="form-control" id="transferAmount" min="0.001" step="0.001" required>
|
||||
<div class="form-text">Available balance: $<span id="availableBalance">{% if wallet_balance %}{{ wallet_balance }}{% else %}0{% endif %}</span></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="transferNote" class="form-label">Note (Optional)</label>
|
||||
<textarea class="form-control" id="transferNote" rows="2" placeholder="Add a note for this transfer"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="transferCreditsBtn">Send Transfer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Wallet hydration and externalized script -->
|
||||
<script type="application/json" id="wallet-hydration">
|
||||
{"currency_symbol": {{ currency_symbol | default(value='$') | json_encode() }}}
|
||||
</script>
|
||||
<script src="/static/js/wallet.js"></script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user