rwda ui implementation

This commit is contained in:
Timur Gordon
2025-04-22 15:36:40 +02:00
parent 34594b95fa
commit 6060831f61
15 changed files with 2690 additions and 27 deletions

View File

@@ -0,0 +1,271 @@
{% extends "base.html" %}
{% block title %}Create New Digital Asset{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">Create New Digital Asset</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/assets">Digital Assets</a></li>
<li class="breadcrumb-item active">Create New Asset</li>
</ol>
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-plus-circle me-1"></i>
Asset Details
</div>
<div class="card-body">
<form id="createAssetForm" method="post" action="/assets/create">
<!-- Basic Information -->
<div class="mb-4">
<h5>Basic Information</h5>
<div class="row">
<div class="col-md-6 mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" name="name" required>
</div>
<div class="col-md-6 mb-3">
<label for="asset_type" class="form-label">Asset Type</label>
<select class="form-select" id="asset_type" name="asset_type" required>
{% for type_value, type_label in asset_types %}
<option value="{{ type_value }}">{{ type_label }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea class="form-control" id="description" name="description" rows="3" required></textarea>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="image_url" class="form-label">Image URL (optional)</label>
<input type="url" class="form-control" id="image_url" name="image_url">
<div class="form-text">URL to an image representing this asset</div>
</div>
<div class="col-md-6 mb-3">
<label for="external_url" class="form-label">External URL (optional)</label>
<input type="url" class="form-control" id="external_url" name="external_url">
<div class="form-text">URL to an external resource for this asset</div>
</div>
</div>
</div>
<!-- Blockchain Information -->
<div class="mb-4">
<h5>Blockchain Information (optional)</h5>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="has_blockchain_info" name="has_blockchain_info">
<label class="form-check-label" for="has_blockchain_info">
This asset has blockchain information
</label>
</div>
<div id="blockchainInfoSection" style="display: none;">
<div class="row">
<div class="col-md-6 mb-3">
<label for="blockchain" class="form-label">Blockchain</label>
<input type="text" class="form-control" id="blockchain" name="blockchain">
</div>
<div class="col-md-6 mb-3">
<label for="token_id" class="form-label">Token ID</label>
<input type="text" class="form-control" id="token_id" name="token_id">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="contract_address" class="form-label">Contract Address</label>
<input type="text" class="form-control" id="contract_address" name="contract_address">
</div>
<div class="col-md-6 mb-3">
<label for="owner_address" class="form-label">Owner Address</label>
<input type="text" class="form-control" id="owner_address" name="owner_address">
</div>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="transaction_hash" class="form-label">Transaction Hash (optional)</label>
<input type="text" class="form-control" id="transaction_hash" name="transaction_hash">
</div>
<div class="col-md-6 mb-3">
<label for="block_number" class="form-label">Block Number (optional)</label>
<input type="number" class="form-control" id="block_number" name="block_number">
</div>
</div>
</div>
</div>
<!-- Initial Valuation -->
<div class="mb-4">
<h5>Initial Valuation (optional)</h5>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="has_valuation" name="has_valuation">
<label class="form-check-label" for="has_valuation">
Add an initial valuation for this asset
</label>
</div>
<div id="valuationSection" style="display: none;">
<div class="row">
<div class="col-md-4 mb-3">
<label for="value" class="form-label">Value</label>
<input type="number" class="form-control" id="value" name="value" step="0.01">
</div>
<div class="col-md-4 mb-3">
<label for="currency" class="form-label">Currency</label>
<input type="text" class="form-control" id="currency" name="currency" value="USD">
</div>
<div class="col-md-4 mb-3">
<label for="source" class="form-label">Source</label>
<input type="text" class="form-control" id="source" name="source">
</div>
</div>
<div class="mb-3">
<label for="valuation_notes" class="form-label">Notes</label>
<textarea class="form-control" id="valuation_notes" name="valuation_notes" rows="2"></textarea>
</div>
</div>
</div>
<!-- Metadata -->
<div class="mb-4">
<h5>Additional Metadata (optional)</h5>
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" id="has_metadata" name="has_metadata">
<label class="form-check-label" for="has_metadata">
Add additional metadata for this asset
</label>
</div>
<div id="metadataSection" style="display: none;">
<div class="mb-3">
<label for="metadata" class="form-label">Metadata (JSON format)</label>
<textarea class="form-control" id="metadata" name="metadata" rows="5"></textarea>
<div class="form-text">Enter additional metadata in JSON format</div>
</div>
</div>
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<a href="/assets" class="btn btn-secondary me-md-2">Cancel</a>
<button type="submit" class="btn btn-primary">Create Asset</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Toggle blockchain info section
const hasBlockchainInfo = document.getElementById('has_blockchain_info');
const blockchainInfoSection = document.getElementById('blockchainInfoSection');
hasBlockchainInfo.addEventListener('change', function() {
blockchainInfoSection.style.display = this.checked ? 'block' : 'none';
});
// Toggle valuation section
const hasValuation = document.getElementById('has_valuation');
const valuationSection = document.getElementById('valuationSection');
hasValuation.addEventListener('change', function() {
valuationSection.style.display = this.checked ? 'block' : 'none';
});
// Toggle metadata section
const hasMetadata = document.getElementById('has_metadata');
const metadataSection = document.getElementById('metadataSection');
hasMetadata.addEventListener('change', function() {
metadataSection.style.display = this.checked ? 'block' : 'none';
});
// Form validation
const form = document.getElementById('createAssetForm');
form.addEventListener('submit', function(event) {
let isValid = true;
// Validate required fields
const name = document.getElementById('name').value.trim();
const description = document.getElementById('description').value.trim();
if (!name) {
isValid = false;
document.getElementById('name').classList.add('is-invalid');
} else {
document.getElementById('name').classList.remove('is-invalid');
}
if (!description) {
isValid = false;
document.getElementById('description').classList.add('is-invalid');
} else {
document.getElementById('description').classList.remove('is-invalid');
}
// Validate blockchain info if checked
if (hasBlockchainInfo.checked) {
const blockchain = document.getElementById('blockchain').value.trim();
const tokenId = document.getElementById('token_id').value.trim();
const contractAddress = document.getElementById('contract_address').value.trim();
const ownerAddress = document.getElementById('owner_address').value.trim();
if (!blockchain || !tokenId || !contractAddress || !ownerAddress) {
isValid = false;
if (!blockchain) document.getElementById('blockchain').classList.add('is-invalid');
if (!tokenId) document.getElementById('token_id').classList.add('is-invalid');
if (!contractAddress) document.getElementById('contract_address').classList.add('is-invalid');
if (!ownerAddress) document.getElementById('owner_address').classList.add('is-invalid');
}
}
// Validate valuation if checked
if (hasValuation.checked) {
const value = document.getElementById('value').value.trim();
const currency = document.getElementById('currency').value.trim();
const source = document.getElementById('source').value.trim();
if (!value || !currency || !source) {
isValid = false;
if (!value) document.getElementById('value').classList.add('is-invalid');
if (!currency) document.getElementById('currency').classList.add('is-invalid');
if (!source) document.getElementById('source').classList.add('is-invalid');
}
}
// Validate metadata if checked
if (hasMetadata.checked) {
const metadata = document.getElementById('metadata').value.trim();
if (metadata) {
try {
JSON.parse(metadata);
document.getElementById('metadata').classList.remove('is-invalid');
} catch (e) {
isValid = false;
document.getElementById('metadata').classList.add('is-invalid');
}
}
}
if (!isValid) {
event.preventDefault();
alert('Please fix the errors in the form before submitting.');
}
});
});
</script>
<style>
.form-check-input:checked {
background-color: #0d6efd;
border-color: #0d6efd;
}
.is-invalid {
border-color: #dc3545;
}
</style>
{% endblock %}

View File

@@ -0,0 +1,556 @@
{% extends "base.html" %}
{% block title %}Asset Details - {{ asset.name }}{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">Asset Details</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/assets">Digital Assets</a></li>
<li class="breadcrumb-item active">{{ asset.name }}</li>
</ol>
<!-- Asset Overview -->
<div class="row">
<div class="col-xl-4">
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-info-circle me-1"></i>
Asset Information
</div>
<div class="card-body">
<div class="text-center mb-4">
{% if asset.image_url %}
<img src="{{ asset.image_url }}" alt="{{ asset.name }}" class="img-fluid asset-image mb-3">
{% else %}
<div class="asset-placeholder mb-3">
<i class="fas fa-cube fa-5x"></i>
</div>
{% endif %}
<h3>{{ asset.name }}</h3>
<div>
{% if asset.status == "Active" %}
<span class="badge bg-success">{{ asset.status }}</span>
{% elif asset.status == "For Sale" %}
<span class="badge bg-warning">{{ asset.status }}</span>
{% elif asset.status == "Locked" %}
<span class="badge bg-secondary">{{ asset.status }}</span>
{% elif asset.status == "Transferred" %}
<span class="badge bg-info">{{ asset.status }}</span>
{% elif asset.status == "Archived" %}
<span class="badge bg-danger">{{ asset.status }}</span>
{% else %}
<span class="badge bg-primary">{{ asset.status }}</span>
{% endif %}
<span class="badge bg-primary">{{ asset.asset_type }}</span>
</div>
</div>
<div class="mb-3">
<h5>Description</h5>
<p>{{ asset.description }}</p>
</div>
<div class="mb-3">
<h5>Current Valuation</h5>
{% if asset.current_valuation %}
<h3 class="text-primary">{{ asset.valuation_currency }}{{ asset.current_valuation }}</h3>
<small class="text-muted">Last updated: {{ asset.valuation_date }}</small>
{% else %}
<p>No valuation available</p>
{% endif %}
</div>
<div class="mb-3">
<h5>Owner Information</h5>
<p><strong>Owner:</strong> {{ asset.owner_name }}</p>
<p><strong>Owner ID:</strong> {{ asset.owner_id }}</p>
</div>
<div class="mb-3">
<h5>Dates</h5>
<p><strong>Created:</strong> {{ asset.created_at }}</p>
<p><strong>Last Updated:</strong> {{ asset.updated_at }}</p>
</div>
{% if asset.external_url %}
<div class="mb-3">
<a href="{{ asset.external_url }}" target="_blank" class="btn btn-outline-primary">
<i class="fas fa-external-link-alt me-1"></i> View External Resource
</a>
</div>
{% endif %}
</div>
<div class="card-footer">
<div class="d-grid gap-2">
<button class="btn btn-primary" type="button" data-bs-toggle="modal" data-bs-target="#valuationModal">
<i class="fas fa-dollar-sign me-1"></i> Add Valuation
</button>
<button class="btn btn-secondary" type="button" data-bs-toggle="modal" data-bs-target="#transactionModal">
<i class="fas fa-exchange-alt me-1"></i> Record Transaction
</button>
<button class="btn btn-warning" type="button" data-bs-toggle="modal" data-bs-target="#statusModal">
<i class="fas fa-edit me-1"></i> Change Status
</button>
</div>
</div>
</div>
</div>
<div class="col-xl-8">
<!-- Blockchain Information -->
{% if asset.blockchain_info %}
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-link me-1"></i>
Blockchain Information
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<p><strong>Blockchain:</strong> {{ asset.blockchain_info.blockchain }}</p>
<p><strong>Token ID:</strong> {{ asset.blockchain_info.token_id }}</p>
<p><strong>Contract Address:</strong>
<code class="blockchain-address">{{ asset.blockchain_info.contract_address }}</code>
</p>
</div>
<div class="col-md-6">
<p><strong>Owner Address:</strong>
<code class="blockchain-address">{{ asset.blockchain_info.owner_address }}</code>
</p>
{% if asset.blockchain_info.transaction_hash %}
<p><strong>Transaction Hash:</strong>
<code class="blockchain-address">{{ asset.blockchain_info.transaction_hash }}</code>
</p>
{% endif %}
{% if asset.blockchain_info.block_number %}
<p><strong>Block Number:</strong> {{ asset.blockchain_info.block_number }}</p>
{% endif %}
{% if asset.blockchain_info.timestamp %}
<p><strong>Timestamp:</strong> {{ asset.blockchain_info.timestamp }}</p>
{% endif %}
</div>
</div>
</div>
</div>
{% endif %}
<!-- Valuation History Chart -->
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-chart-line me-1"></i>
Valuation History
</div>
<div class="card-body">
{% if valuation_history and valuation_history|length > 0 %}
<canvas id="valuationChart" width="100%" height="40"></canvas>
{% else %}
<div class="alert alert-info">
No valuation history available for this asset.
</div>
{% endif %}
</div>
</div>
<!-- Valuation History Table -->
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-history me-1"></i>
Valuation History
</div>
<div class="card-body">
{% if asset.valuation_history and asset.valuation_history|length > 0 %}
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Date</th>
<th>Value</th>
<th>Currency</th>
<th>Source</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{% for valuation in asset.valuation_history %}
<tr>
<td>{{ valuation.date }}</td>
<td>{{ valuation.value }}</td>
<td>{{ valuation.currency }}</td>
<td>{{ valuation.source }}</td>
<td>{% if valuation.notes %}{{ valuation.notes }}{% else %}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="alert alert-info">
No valuation history available for this asset.
</div>
{% endif %}
</div>
</div>
<!-- Transaction History -->
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-exchange-alt me-1"></i>
Transaction History
</div>
<div class="card-body">
{% if asset.transaction_history and asset.transaction_history|length > 0 %}
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Date</th>
<th>Type</th>
<th>From</th>
<th>To</th>
<th>Amount</th>
<th>Transaction Hash</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{% for transaction in asset.transaction_history %}
<tr>
<td>{{ transaction.date }}</td>
<td>{{ transaction.transaction_type }}</td>
<td>
{% if transaction.from_address %}
<code class="blockchain-address-small">{{ transaction.from_address }}</code>
{% else %}
N/A
{% endif %}
</td>
<td>
{% if transaction.to_address %}
<code class="blockchain-address-small">{{ transaction.to_address }}</code>
{% else %}
N/A
{% endif %}
</td>
<td>
{% if transaction.amount %}
{{ transaction.currency }}{{ transaction.amount }}
{% else %}
N/A
{% endif %}
</td>
<td>
{% if transaction.transaction_hash %}
<code class="blockchain-address-small">{{ transaction.transaction_hash }}</code>
{% else %}
N/A
{% endif %}
</td>
<td>{% if transaction.notes %}{{ transaction.notes }}{% else %}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="alert alert-info">
No transaction history available for this asset.
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Valuation Modal -->
<div class="modal fade" id="valuationModal" tabindex="-1" aria-labelledby="valuationModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="valuationModalLabel">Add Valuation</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="valuationForm" method="post" action="/assets/{{ asset.id }}/valuation">
<div class="mb-3">
<label for="value" class="form-label">Value</label>
<input type="number" class="form-control" id="value" name="value" step="0.01" required>
</div>
<div class="mb-3">
<label for="currency" class="form-label">Currency</label>
<input type="text" class="form-control" id="currency" name="currency" value="USD" required>
</div>
<div class="mb-3">
<label for="source" class="form-label">Source</label>
<input type="text" class="form-control" id="source" name="source" required>
</div>
<div class="mb-3">
<label for="notes" class="form-label">Notes</label>
<textarea class="form-control" id="notes" name="notes" rows="3"></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="saveValuationBtn">Save</button>
</div>
</div>
</div>
</div>
<!-- Transaction Modal -->
<div class="modal fade" id="transactionModal" tabindex="-1" aria-labelledby="transactionModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="transactionModalLabel">Record Transaction</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="transactionForm" method="post" action="/assets/{{ asset.id }}/transaction">
<div class="mb-3">
<label for="transaction_type" class="form-label">Transaction Type</label>
<select class="form-select" id="transaction_type" name="transaction_type" required>
<option value="Purchase">Purchase</option>
<option value="Sale">Sale</option>
<option value="Transfer">Transfer</option>
<option value="Mint">Mint</option>
<option value="Burn">Burn</option>
<option value="Licensing">Licensing</option>
<option value="Other">Other</option>
</select>
</div>
<div class="mb-3">
<label for="from_address" class="form-label">From Address</label>
<input type="text" class="form-control" id="from_address" name="from_address">
</div>
<div class="mb-3">
<label for="to_address" class="form-label">To Address</label>
<input type="text" class="form-control" id="to_address" name="to_address">
</div>
<div class="mb-3">
<label for="amount" class="form-label">Amount</label>
<input type="number" class="form-control" id="amount" name="amount" step="0.01">
</div>
<div class="mb-3">
<label for="transaction_currency" class="form-label">Currency</label>
<input type="text" class="form-control" id="transaction_currency" name="currency" value="USD">
</div>
<div class="mb-3">
<label for="transaction_hash" class="form-label">Transaction Hash</label>
<input type="text" class="form-control" id="transaction_hash" name="transaction_hash">
</div>
<div class="mb-3">
<label for="transaction_notes" class="form-label">Notes</label>
<textarea class="form-control" id="transaction_notes" name="notes" rows="3"></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="saveTransactionBtn">Save</button>
</div>
</div>
</div>
</div>
<!-- Status Modal -->
<div class="modal fade" id="statusModal" tabindex="-1" aria-labelledby="statusModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="statusModalLabel">Change Asset Status</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="statusForm" method="post" action="/assets/{{ asset.id }}/status/">
<div class="mb-3">
<label for="newStatus" class="form-label">New Status</label>
<select class="form-select" id="newStatus" name="status">
<option value="Active" {% if asset.status == "Active" %}selected{% endif %}>Active</option>
<option value="Locked" {% if asset.status == "Locked" %}selected{% endif %}>Locked</option>
<option value="ForSale" {% if asset.status == "For Sale" %}selected{% endif %}>For Sale</option>
<option value="Transferred" {% if asset.status == "Transferred" %}selected{% endif %}>Transferred</option>
<option value="Archived" {% if asset.status == "Archived" %}selected{% endif %}>Archived</option>
</select>
</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="saveStatusBtn">Save Changes</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Valuation History Chart
{% if valuation_history and valuation_history|length > 0 %}
const ctx = document.getElementById('valuationChart');
const dates = [
{% for point in valuation_history %}
"{{ point.date }}"{% if not loop.last %},{% endif %}
{% endfor %}
];
const values = [
{% for point in valuation_history %}
{{ point.value }}{% if not loop.last %},{% endif %}
{% endfor %}
];
new Chart(ctx, {
type: 'line',
data: {
labels: dates,
datasets: [{
label: 'Valuation ({{ valuation_history[0].currency }})',
data: values,
lineTension: 0.3,
backgroundColor: "rgba(78, 115, 223, 0.05)",
borderColor: "rgba(78, 115, 223, 1)",
pointRadius: 3,
pointBackgroundColor: "rgba(78, 115, 223, 1)",
pointBorderColor: "rgba(78, 115, 223, 1)",
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(78, 115, 223, 1)",
pointHoverBorderColor: "rgba(78, 115, 223, 1)",
pointHitRadius: 10,
pointBorderWidth: 2,
fill: true
}],
},
options: {
maintainAspectRatio: false,
scales: {
x: {
grid: {
display: false,
drawBorder: false
},
ticks: {
maxTicksLimit: 7
}
},
y: {
ticks: {
maxTicksLimit: 5,
padding: 10,
callback: function(value, index, values) {
return '{{ valuation_history[0].currency }}' + value;
}
},
grid: {
color: "rgb(234, 236, 244)",
zeroLineColor: "rgb(234, 236, 244)",
drawBorder: false,
borderDash: [2],
zeroLineBorderDash: [2]
}
},
},
plugins: {
legend: {
display: false
},
tooltip: {
backgroundColor: "rgb(255,255,255)",
bodyFontColor: "#858796",
titleMarginBottom: 10,
titleFontColor: '#6e707e',
titleFontSize: 14,
borderColor: '#dddfeb',
borderWidth: 1,
xPadding: 15,
yPadding: 15,
displayColors: false,
intersect: false,
mode: 'index',
caretPadding: 10,
callbacks: {
label: function(context) {
var label = context.dataset.label || '';
if (label) {
label += ': ';
}
label += '{{ valuation_history[0].currency }}' + context.parsed.y;
return label;
}
}
}
}
}
});
{% endif %}
// Form submission handlers
const saveValuationBtn = document.getElementById('saveValuationBtn');
if (saveValuationBtn) {
saveValuationBtn.addEventListener('click', function() {
document.getElementById('valuationForm').submit();
});
}
const saveTransactionBtn = document.getElementById('saveTransactionBtn');
if (saveTransactionBtn) {
saveTransactionBtn.addEventListener('click', function() {
document.getElementById('transactionForm').submit();
});
}
const saveStatusBtn = document.getElementById('saveStatusBtn');
if (saveStatusBtn) {
saveStatusBtn.addEventListener('click', function() {
const form = document.getElementById('statusForm');
const newStatus = document.getElementById('newStatus').value;
form.action = form.action + newStatus;
form.submit();
});
}
});
</script>
<style>
.asset-image {
max-height: 200px;
border-radius: 8px;
}
.asset-placeholder {
width: 100%;
height: 200px;
display: flex;
align-items: center;
justify-content: center;
background-color: #f8f9fa;
border-radius: 8px;
color: #6c757d;
}
.blockchain-address {
display: inline-block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.85rem;
}
.blockchain-address-small {
display: inline-block;
max-width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 0.75rem;
}
</style>
{% endblock %}

View File

@@ -0,0 +1,140 @@
{% extends "base.html" %}
{% block title %}Digital Assets Dashboard{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">Digital Assets Dashboard</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item active">Digital Assets</li>
</ol>
<!-- Stats Cards -->
<div class="row">
<div class="col-xl-3 col-md-6">
<div class="card bg-primary text-white mb-4">
<div class="card-body">
<h2 class="display-4">{{ stats.total_assets }}</h2>
<p class="mb-0">Total Assets</p>
</div>
<div class="card-footer d-flex align-items-center justify-content-between">
<a class="small text-white stretched-link" href="/assets/list">View All Assets</a>
<div class="small text-white"><i class="fas fa-angle-right"></i></div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-success text-white mb-4">
<div class="card-body">
<h2 class="display-4">${{ stats.total_value }}</h2>
<p class="mb-0">Total Valuation</p>
</div>
<div class="card-footer d-flex align-items-center justify-content-between">
<a class="small text-white stretched-link" href="/assets/list">View Details</a>
<div class="small text-white"><i class="fas fa-angle-right"></i></div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-warning text-white mb-4">
<div class="card-body">
<h2 class="display-4">{{ stats.assets_by_status.Active }}</h2>
<p class="mb-0">Active Assets</p>
</div>
<div class="card-footer d-flex align-items-center justify-content-between">
<a class="small text-white stretched-link" href="/assets/list">View Active Assets</a>
<div class="small text-white"><i class="fas fa-angle-right"></i></div>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-danger text-white mb-4">
<div class="card-body">
<h2 class="display-4">0</h2>
<p class="mb-0">Pending Transactions</p>
</div>
<div class="card-footer d-flex align-items-center justify-content-between">
<a class="small text-white stretched-link" href="/assets/list">View Transactions</a>
<div class="small text-white"><i class="fas fa-angle-right"></i></div>
</div>
</div>
</div>
</div>
<!-- Asset Types Distribution -->
<div class="row mt-4">
<div class="col-12">
<div class="card mb-4">
<div class="card-header">
<i class="bi bi-pie-chart me-1"></i>
Asset Types Distribution
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Asset Type</th>
<th>Count</th>
</tr>
</thead>
<tbody>
{% for asset_type in assets_by_type %}
<tr>
<td>{{ asset_type.type }}</td>
<td>{{ asset_type.count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Assets Table -->
<div class="row mt-4">
<div class="col-12">
<div class="card mb-4">
<div class="card-header">
<i class="bi bi-table me-1"></i>
Recent Assets
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for asset in recent_assets %}
<tr>
<td>{{ asset.name }}</td>
<td>{{ asset.asset_type }}</td>
<td>{{ asset.status }}</td>
<td>
<a href="/assets/{{ asset.id }}" class="btn btn-sm btn-primary">
<i class="bi bi-eye"></i> View
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="card-footer">
<a href="/assets/list" class="btn btn-primary">View All Assets</a>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@@ -0,0 +1,286 @@
{% extends "base.html" %}
{% block title %}Digital Assets List{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">Digital Assets</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/assets">Digital Assets</a></li>
<li class="breadcrumb-item active">All Assets</li>
</ol>
<!-- Filters -->
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-filter me-1"></i>
Filter Assets
</div>
<div class="card-body">
<div class="row">
<div class="col-md-3 mb-3">
<label for="assetTypeFilter" class="form-label">Asset Type</label>
<select class="form-select" id="assetTypeFilter">
<option value="all">All Types</option>
<option value="NFT">NFT</option>
<option value="Token">Token</option>
<option value="RealEstate">Real Estate</option>
<option value="Commodity">Commodity</option>
<option value="Share">Share</option>
<option value="Bond">Bond</option>
<option value="IntellectualProperty">Intellectual Property</option>
<option value="Other">Other</option>
</select>
</div>
<div class="col-md-3 mb-3">
<label for="statusFilter" class="form-label">Status</label>
<select class="form-select" id="statusFilter">
<option value="all">All Statuses</option>
<option value="Active">Active</option>
<option value="Locked">Locked</option>
<option value="ForSale">For Sale</option>
<option value="Transferred">Transferred</option>
<option value="Archived">Archived</option>
</select>
</div>
<div class="col-md-3 mb-3">
<label for="valuationFilter" class="form-label">Valuation</label>
<select class="form-select" id="valuationFilter">
<option value="all">All Valuations</option>
<option value="under1000">Under $1,000</option>
<option value="1000to10000">$1,000 - $10,000</option>
<option value="10000to100000">$10,000 - $100,000</option>
<option value="over100000">Over $100,000</option>
</select>
</div>
<div class="col-md-3 mb-3">
<label for="searchInput" class="form-label">Search</label>
<input type="text" class="form-control" id="searchInput" placeholder="Search by name or description">
</div>
</div>
<div class="row">
<div class="col-12">
<button id="applyFilters" class="btn btn-primary">Apply Filters</button>
<button id="resetFilters" class="btn btn-secondary">Reset</button>
</div>
</div>
</div>
</div>
<!-- Assets Table -->
<div class="card mb-4">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<div>
<i class="fas fa-table me-1"></i>
All Digital Assets
</div>
<div>
<a href="/assets/create" class="btn btn-primary btn-sm">
<i class="fas fa-plus"></i> Create New Asset
</a>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-hover" id="assetsTable">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Status</th>
<th>Owner</th>
<th>Valuation</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for asset in assets %}
<tr class="asset-row"
data-type="{{ asset.asset_type }}"
data-status="{{ asset.status }}"
data-valuation="{% if asset.current_valuation %}{{ asset.current_valuation }}{% else %}0{% endif %}">
<td>
{% if asset.image_url %}
<img src="{{ asset.image_url }}" alt="{{ asset.name }}" class="asset-thumbnail me-2">
{% endif %}
{{ asset.name }}
</td>
<td>{{ asset.asset_type }}</td>
<td>
{% if asset.status == "Active" %}
<span class="badge bg-success">{{ asset.status }}</span>
{% elif asset.status == "For Sale" %}
<span class="badge bg-warning">{{ asset.status }}</span>
{% elif asset.status == "Locked" %}
<span class="badge bg-secondary">{{ asset.status }}</span>
{% elif asset.status == "Transferred" %}
<span class="badge bg-info">{{ asset.status }}</span>
{% elif asset.status == "Archived" %}
<span class="badge bg-danger">{{ asset.status }}</span>
{% else %}
<span class="badge bg-primary">{{ asset.status }}</span>
{% endif %}
</td>
<td>{{ asset.owner_name }}</td>
<td>
{% if asset.current_valuation %}
{{ asset.valuation_currency }}{{ asset.current_valuation }}
{% else %}
N/A
{% endif %}
</td>
<td>{{ asset.created_at }}</td>
<td>
<div class="btn-group" role="group">
<a href="/assets/{{ asset.id }}" class="btn btn-sm btn-primary">
<i class="fas fa-eye"></i>
</a>
{% if asset.status == "Active" %}
<button type="button" class="btn btn-sm btn-warning" data-bs-toggle="modal" data-bs-target="#statusModal" data-asset-id="{{ asset.id }}">
<i class="fas fa-exchange-alt"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Status Change Modal -->
<div class="modal fade" id="statusModal" tabindex="-1" aria-labelledby="statusModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="statusModalLabel">Change Asset Status</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="statusForm" method="post" action="">
<div class="mb-3">
<label for="newStatus" class="form-label">New Status</label>
<select class="form-select" id="newStatus" name="status">
<option value="Active">Active</option>
<option value="Locked">Locked</option>
<option value="ForSale">For Sale</option>
<option value="Transferred">Transferred</option>
<option value="Archived">Archived</option>
</select>
</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="saveStatusBtn">Save Changes</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Status modal functionality
const statusModal = document.getElementById('statusModal');
if (statusModal) {
statusModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const assetId = button.getAttribute('data-asset-id');
const form = document.getElementById('statusForm');
form.action = `/assets/${assetId}/status/`;
});
const saveStatusBtn = document.getElementById('saveStatusBtn');
saveStatusBtn.addEventListener('click', function() {
const form = document.getElementById('statusForm');
const newStatus = document.getElementById('newStatus').value;
form.action = form.action + newStatus;
form.submit();
});
}
// Filtering functionality
const applyFilters = document.getElementById('applyFilters');
if (applyFilters) {
applyFilters.addEventListener('click', function() {
filterAssets();
});
}
const resetFilters = document.getElementById('resetFilters');
if (resetFilters) {
resetFilters.addEventListener('click', function() {
document.getElementById('assetTypeFilter').value = 'all';
document.getElementById('statusFilter').value = 'all';
document.getElementById('valuationFilter').value = 'all';
document.getElementById('searchInput').value = '';
filterAssets();
});
}
const searchInput = document.getElementById('searchInput');
if (searchInput) {
searchInput.addEventListener('keyup', function(event) {
if (event.key === 'Enter') {
filterAssets();
}
});
}
function filterAssets() {
const typeFilter = document.getElementById('assetTypeFilter').value;
const statusFilter = document.getElementById('statusFilter').value;
const valuationFilter = document.getElementById('valuationFilter').value;
const searchText = document.getElementById('searchInput').value.toLowerCase();
const rows = document.querySelectorAll('#assetsTable tbody tr');
rows.forEach(row => {
const type = row.getAttribute('data-type');
const status = row.getAttribute('data-status');
const valuation = parseFloat(row.getAttribute('data-valuation'));
const name = row.querySelector('td:first-child').textContent.toLowerCase();
let typeMatch = typeFilter === 'all' || type === typeFilter;
let statusMatch = statusFilter === 'all' || status === statusFilter;
let searchMatch = searchText === '' || name.includes(searchText);
let valuationMatch = true;
if (valuationFilter === 'under1000') {
valuationMatch = valuation < 1000;
} else if (valuationFilter === '1000to10000') {
valuationMatch = valuation >= 1000 && valuation < 10000;
} else if (valuationFilter === '10000to100000') {
valuationMatch = valuation >= 10000 && valuation < 100000;
} else if (valuationFilter === 'over100000') {
valuationMatch = valuation >= 100000;
}
if (typeMatch && statusMatch && valuationMatch && searchMatch) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
}
});
</script>
<style>
.asset-thumbnail {
width: 30px;
height: 30px;
object-fit: cover;
border-radius: 4px;
}
</style>
{% endblock %}

View File

@@ -0,0 +1,373 @@
{% extends "base.html" %}
{% block title %}My Digital Assets{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">My Digital Assets</h1>
<ol class="breadcrumb mb-4">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/assets">Digital Assets</a></li>
<li class="breadcrumb-item active">My Assets</li>
</ol>
<!-- Summary Cards -->
<div class="row">
<div class="col-xl-3 col-md-6">
<div class="card bg-primary text-white mb-4">
<div class="card-body">
<h2 class="display-4">{{ assets | length }}</h2>
<p class="mb-0">Total Assets</p>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-success text-white mb-4">
<div class="card-body">
{% set active_count = 0 %}
{% for asset in assets %}
{% if asset.status == "Active" %}
{% set active_count = active_count + 1 %}
{% endif %}
{% endfor %}
<h2 class="display-4">{{ active_count }}</h2>
<p class="mb-0">Active Assets</p>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-warning text-white mb-4">
<div class="card-body">
{% set for_sale_count = 0 %}
{% for asset in assets %}
{% if asset.status == "For Sale" %}
{% set for_sale_count = for_sale_count + 1 %}
{% endif %}
{% endfor %}
<h2 class="display-4">{{ for_sale_count }}</h2>
<p class="mb-0">For Sale</p>
</div>
</div>
</div>
<div class="col-xl-3 col-md-6">
<div class="card bg-info text-white mb-4">
<div class="card-body">
{% set total_value = 0 %}
{% for asset in assets %}
{% if asset.current_valuation %}
{% set total_value = total_value + asset.current_valuation %}
{% endif %}
{% endfor %}
<h2 class="display-4">${% if total_value %}{{ total_value }}{% else %}0.00{% endif %}</h2>
<p class="mb-0">Total Value</p>
</div>
</div>
</div>
</div>
<!-- Assets Table -->
<div class="card mb-4">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<div>
<i class="fas fa-table me-1"></i>
My Digital Assets
</div>
<div>
<a href="/assets/create" class="btn btn-primary btn-sm">
<i class="fas fa-plus"></i> Create New Asset
</a>
</div>
</div>
</div>
<div class="card-body">
{% if assets and assets|length > 0 %}
<div class="table-responsive">
<table class="table table-striped table-hover" id="myAssetsTable">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Status</th>
<th>Valuation</th>
<th>Created</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for asset in assets %}
<tr>
<td>
{% if asset.image_url %}
<img src="{{ asset.image_url }}" alt="{{ asset.name }}" class="asset-thumbnail me-2">
{% endif %}
{{ asset.name }}
</td>
<td>{{ asset.asset_type }}</td>
<td>
{% if asset.status == "Active" %}
<span class="badge bg-success">{{ asset.status }}</span>
{% elif asset.status == "For Sale" %}
<span class="badge bg-warning">{{ asset.status }}</span>
{% elif asset.status == "Locked" %}
<span class="badge bg-secondary">{{ asset.status }}</span>
{% elif asset.status == "Transferred" %}
<span class="badge bg-info">{{ asset.status }}</span>
{% elif asset.status == "Archived" %}
<span class="badge bg-danger">{{ asset.status }}</span>
{% else %}
<span class="badge bg-primary">{{ asset.status }}</span>
{% endif %}
</td>
<td>
{% if asset.current_valuation %}
{{ asset.valuation_currency }}{{ asset.current_valuation }}
{% else %}
N/A
{% endif %}
</td>
<td>{{ asset.created_at }}</td>
<td>
<div class="btn-group" role="group">
<a href="/assets/{{ asset.id }}" class="btn btn-sm btn-primary">
<i class="fas fa-eye"></i>
</a>
<button type="button" class="btn btn-sm btn-warning" data-bs-toggle="modal" data-bs-target="#statusModal" data-asset-id="{{ asset.id }}">
<i class="fas fa-exchange-alt"></i>
</button>
<button type="button" class="btn btn-sm btn-success" data-bs-toggle="modal" data-bs-target="#valuationModal" data-asset-id="{{ asset.id }}">
<i class="fas fa-dollar-sign"></i>
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="alert alert-info">
<p>You don't have any digital assets yet.</p>
<a href="/assets/create" class="btn btn-primary">Create Your First Asset</a>
</div>
{% endif %}
</div>
</div>
<!-- Asset Types Distribution -->
<div class="row">
<div class="col-xl-6">
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-chart-pie me-1"></i>
Asset Types Distribution
</div>
<div class="card-body">
<canvas id="assetTypesChart" width="100%" height="40"></canvas>
</div>
</div>
</div>
<div class="col-xl-6">
<div class="card mb-4">
<div class="card-header">
<i class="fas fa-chart-bar me-1"></i>
Asset Value Distribution
</div>
<div class="card-body">
<canvas id="assetValueChart" width="100%" height="40"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Status Change Modal -->
<div class="modal fade" id="statusModal" tabindex="-1" aria-labelledby="statusModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="statusModalLabel">Change Asset Status</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="statusForm" method="post" action="">
<div class="mb-3">
<label for="newStatus" class="form-label">New Status</label>
<select class="form-select" id="newStatus" name="status">
<option value="Active">Active</option>
<option value="Locked">Locked</option>
<option value="ForSale">For Sale</option>
<option value="Transferred">Transferred</option>
<option value="Archived">Archived</option>
</select>
</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="saveStatusBtn">Save Changes</button>
</div>
</div>
</div>
</div>
<!-- Valuation Modal -->
<div class="modal fade" id="valuationModal" tabindex="-1" aria-labelledby="valuationModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="valuationModalLabel">Add Valuation</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form id="valuationForm" method="post" action="">
<div class="mb-3">
<label for="value" class="form-label">Value</label>
<input type="number" class="form-control" id="value" name="value" step="0.01" required>
</div>
<div class="mb-3">
<label for="currency" class="form-label">Currency</label>
<input type="text" class="form-control" id="currency" name="currency" value="USD" required>
</div>
<div class="mb-3">
<label for="source" class="form-label">Source</label>
<input type="text" class="form-control" id="source" name="source" required>
</div>
<div class="mb-3">
<label for="notes" class="form-label">Notes</label>
<textarea class="form-control" id="notes" name="notes" rows="3"></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="saveValuationBtn">Save</button>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
// Status modal functionality
const statusModal = document.getElementById('statusModal');
if (statusModal) {
statusModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const assetId = button.getAttribute('data-asset-id');
const form = document.getElementById('statusForm');
form.action = `/assets/${assetId}/status/`;
});
const saveStatusBtn = document.getElementById('saveStatusBtn');
saveStatusBtn.addEventListener('click', function() {
const form = document.getElementById('statusForm');
const newStatus = document.getElementById('newStatus').value;
form.action = form.action + newStatus;
form.submit();
});
}
// Valuation modal functionality
const valuationModal = document.getElementById('valuationModal');
if (valuationModal) {
valuationModal.addEventListener('show.bs.modal', function(event) {
const button = event.relatedTarget;
const assetId = button.getAttribute('data-asset-id');
const form = document.getElementById('valuationForm');
form.action = `/assets/${assetId}/valuation`;
});
const saveValuationBtn = document.getElementById('saveValuationBtn');
saveValuationBtn.addEventListener('click', function() {
document.getElementById('valuationForm').submit();
});
}
// Asset Types Chart
const assetTypesCtx = document.getElementById('assetTypesChart');
if (assetTypesCtx) {
// Count assets by type
const assetTypes = {};
{% for asset in assets %}
if (!assetTypes['{{ asset.asset_type }}']) {
assetTypes['{{ asset.asset_type }}'] = 0;
}
assetTypes['{{ asset.asset_type }}']++;
{% endfor %}
const typeLabels = Object.keys(assetTypes);
const typeCounts = Object.values(assetTypes);
new Chart(assetTypesCtx, {
type: 'pie',
data: {
labels: typeLabels,
datasets: [{
data: typeCounts,
backgroundColor: [
'#4e73df', '#1cc88a', '#36b9cc', '#f6c23e',
'#e74a3b', '#858796', '#5a5c69', '#2c9faf'
],
}],
},
options: {
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
}
}
},
});
}
// Asset Value Chart
const assetValueCtx = document.getElementById('assetValueChart');
if (assetValueCtx) {
// Prepare data for assets with valuation
const assetNames = [];
const assetValues = [];
{% for asset in assets %}
{% if asset.current_valuation %}
assetNames.push('{{ asset.name }}');
assetValues.push({{ asset.current_valuation }});
{% endif %}
{% endfor %}
new Chart(assetValueCtx, {
type: 'bar',
data: {
labels: assetNames,
datasets: [{
label: 'Asset Value ($)',
data: assetValues,
backgroundColor: '#4e73df',
}],
},
options: {
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
},
});
}
});
</script>
<style>
.asset-thumbnail {
width: 30px;
height: 30px;
object-fit: cover;
border-radius: 4px;
}
</style>
{% endblock %}

View File

@@ -76,6 +76,7 @@
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="/tickets/new">New Ticket</a></li>
<li><a class="dropdown-item" href="/my-tickets">My Tickets</a></li>
<li><a class="dropdown-item" href="/assets/my">My Assets</a></li>
<li><a class="dropdown-item" href="/governance/my-votes">My Votes</a></li>
{% if user.role == "Admin" %}
<li><a class="dropdown-item" href="/admin">Admin Panel</a></li>
@@ -127,6 +128,11 @@
<i class="bi bi-file-earmark-text me-2"></i> Contracts
</a>
</li>
<li class="nav-item">
<a class="nav-link d-flex align-items-center ps-3 py-2 {% if active_page == 'assets' %}active fw-bold border-start border-4 border-primary bg-light{% endif %}" href="/assets">
<i class="bi bi-coin me-2"></i> Digital Assets
</a>
</li>
<li class="nav-item">
<a class="nav-link d-flex align-items-center ps-3 py-2 {% if active_page == 'editor' %}active fw-bold border-start border-4 border-primary bg-light{% endif %}" href="/editor">
<i class="bi bi-markdown me-2"></i> Markdown Editor
@@ -169,7 +175,7 @@
<span>Convenience, Safety and Privacy</span>
</div>
<div>
<span>&copy; {{ now(year=true) }} Zanzibar Autonomous Zone. All rights reserved.</span>
<span>&copy; 2024 Zanzibar Autonomous Zone. All rights reserved.</span>
</div>
</div>
</footer>

View File

@@ -14,7 +14,7 @@
<div class="alert alert-danger">
<p class="mb-2"><strong>Error Message:</strong></p>
<pre class="p-3 bg-light border rounded"><code>{{ error | default(value="Unknown error") }}</code></pre>
<pre class="p-3 bg-light border rounded"><code>{% if error %}{{ error }}{% else %}Unknown error{% endif %}</code></pre>
</div>
{% if error_details is defined and error_details %}

View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
</head>
<body>
<h1>Test Page</h1>
<p>This is a simple test page to verify template rendering.</p>
</body>
</html>

View File

@@ -0,0 +1,10 @@
{% extends "base.html" %}
{% block title %}Test Base Template{% endblock %}
{% block content %}
<div class="container-fluid px-4">
<h1 class="mt-4">Test Base Template</h1>
<p>This is a simplified template for testing that extends base.html.</p>
</div>
{% endblock %}