267 lines
12 KiB
PHP
267 lines
12 KiB
PHP
<?php
|
|
|
|
/**
|
|
* cry01_renderer.php — All HTML rendering for cry01.
|
|
* Knows nothing about network calls or POST handling.
|
|
* Reads config and cache via cry01_chain.php functions.
|
|
*/
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// ASSOCIATION LANDING
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function cry01_render_landing($association_slug, $access) {
|
|
// Renders the main cry01 page: balance display + signal board.
|
|
$raw = @file_get_contents('addon/vs01/config.json');
|
|
$cfg = $raw ? json_decode($raw, true) : [];
|
|
$assoc = $cfg['associations'][$association_slug] ?? [];
|
|
$name = cry01_h($assoc['name'] ?? $association_slug);
|
|
|
|
$out = '<div class="cry01-content">';
|
|
$out .= '<div class="cry01-header mb-3">';
|
|
$out .= '<h2>' . $name . '</h2>';
|
|
$out .= '<p class="text-muted">Value Layer — Ğ1 balance and capacity signals.</p>';
|
|
$out .= '</div>';
|
|
|
|
// Optional participation notice.
|
|
$out .= '<p class="text-muted small cry01-optional-notice">';
|
|
$out .= 'The Value Layer and the Ğ1 Wallet are <strong>optional</strong>. ';
|
|
$out .= 'Ğ1 is a libre currency independent of fiat, used for valuing and bartering surplus capacity among private individuals. ';
|
|
$out .= 'The Civic Infrastructure implements it for participants who choose to engage in that economy. ';
|
|
$out .= 'It is not required for participation in the diagnostic record system.';
|
|
$out .= '</p>';
|
|
|
|
$out .= cry01_render_balance_display();
|
|
$out .= cry01_render_signal_board($association_slug, $access);
|
|
|
|
if ($access === 'participant') {
|
|
$signal_url = z_root() . '/cry01/' . cry01_h($association_slug) . '/signal';
|
|
$out .= '<div class="mt-3">';
|
|
$out .= '<a href="' . $signal_url . '" class="btn btn-outline-primary btn-sm">Register a Signal</a>';
|
|
$out .= '</div>';
|
|
}
|
|
|
|
if ($access === 'operator') {
|
|
$manage_url = z_root() . '/cry01/' . cry01_h($association_slug) . '/manage';
|
|
$g1_url = z_root() . '/cry01/' . cry01_h($association_slug) . '/g1';
|
|
$out .= '<div class="mt-3 d-flex gap-2">';
|
|
$out .= '<a href="' . $manage_url . '" class="btn btn-sm btn-outline-secondary">Manage</a>';
|
|
$out .= '<a href="' . $g1_url . '" class="btn btn-sm btn-outline-secondary">Ğ1 Candidates</a>';
|
|
$out .= '</div>';
|
|
}
|
|
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// BALANCE DISPLAY
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function cry01_render_balance_display() {
|
|
// Renders the Ğ1 balance from cache. The cached key belongs to whoever last refreshed.
|
|
// Shows staleness if cache is old.
|
|
$cache = cry01_read_cache();
|
|
$balance = $cache['balance'] ?? null;
|
|
$pubkey = $cache['g1_pubkey'] ?? '';
|
|
$refreshed = $cache['refreshed_at'] ?? null;
|
|
|
|
$out = '<div class="cry01-balance-display mb-4">';
|
|
$out .= '<h5 class="cry01-section-label">Ğ1 Balance</h5>';
|
|
|
|
if ($balance === null) {
|
|
$out .= '<p class="text-muted fst-italic">Balance not yet loaded. Unlock your Ğ1 wallet and use Manage to refresh.</p>';
|
|
} else {
|
|
$out .= '<p class="cry01-balance-amount">' . cry01_h($balance) . '</p>';
|
|
if ($pubkey) {
|
|
$out .= '<p class="text-muted small">' . cry01_h(substr($pubkey, 0, 16) . '...') . '</p>';
|
|
}
|
|
if ($refreshed) {
|
|
$stale = cry01_cache_is_stale() ? ' <span class="badge bg-warning text-dark">stale</span>' : '';
|
|
$out .= '<p class="text-muted small">Last refreshed: ' . cry01_h($refreshed) . $stale . '</p>';
|
|
}
|
|
}
|
|
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// SIGNAL BOARD
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function cry01_render_signal_board($association_slug, $access) {
|
|
// Renders the signal board. Visible to participants and operator only.
|
|
if ($access === 'public') {
|
|
return '<div class="alert alert-info">Signal board is visible to verified participants only.</div>';
|
|
}
|
|
|
|
// TODO: load signals from orchestrator spool for this association.
|
|
$out = '<div class="cry01-signal-board mb-4">';
|
|
$out .= '<h5 class="cry01-section-label">Capacity Signals</h5>';
|
|
$out .= '<p class="text-muted fst-italic">No signals posted yet.</p>';
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// SIGNAL FORM
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function cry01_render_signal_form($association_slug, $access) {
|
|
// Renders the capacity signal registration form.
|
|
// The g1_pubkey field is populated by the g1wallet session event when available.
|
|
$config = cry01_load_config();
|
|
$categories = $config['signal_categories'] ?? [];
|
|
$form_url = z_root() . '/cry01/' . cry01_h($association_slug) . '/signal';
|
|
|
|
$out = '<div class="cry01-content">';
|
|
$out .= '<h3>Register a Capacity Signal</h3>';
|
|
$out .= '<p class="text-muted">Describe what you are offering or seeking, denominated in Ğ1.</p>';
|
|
|
|
// Wallet session note — replaced by g1wallet integration once built.
|
|
$out .= '<div class="alert alert-info small">Your Ğ1 public key will be populated automatically once the Ğ1 Wallet addon is installed. Until then, enter it manually below.</div>';
|
|
|
|
$out .= '<form method="post" action="' . $form_url . '" class="cry01-form" novalidate>';
|
|
$out .= cry01_csrf_token();
|
|
|
|
// g1_pubkey — will be read-only and auto-populated by g1wallet session once available.
|
|
$out .= '<div class="mb-3">';
|
|
$out .= '<label class="form-label" for="g1_pubkey">Your Ğ1 Public Key <span class="text-danger">*</span></label>';
|
|
$out .= '<input type="text" class="form-control" id="g1_pubkey" name="g1_pubkey" required
|
|
placeholder="G1..." maxlength="64"
|
|
data-g1wallet-target="pubkey">';
|
|
$out .= '<div class="form-text">Your Ğ1 address. This is your payment address for this signal.</div>';
|
|
$out .= '</div>';
|
|
|
|
// Direction
|
|
$out .= '<div class="mb-3">';
|
|
$out .= '<fieldset><legend class="form-label">Direction <span class="text-danger">*</span></legend>';
|
|
$out .= '<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="radio" id="dir_offer" name="direction" value="offer" required>
|
|
<label class="form-check-label" for="dir_offer">Offering capacity</label>
|
|
</div>';
|
|
$out .= '<div class="form-check form-check-inline">
|
|
<input class="form-check-input" type="radio" id="dir_seek" name="direction" value="seek">
|
|
<label class="form-check-label" for="dir_seek">Seeking capacity</label>
|
|
</div>';
|
|
$out .= '</fieldset></div>';
|
|
|
|
// Category
|
|
if ($categories) {
|
|
$out .= '<div class="mb-3">';
|
|
$out .= '<label class="form-label" for="category_id">Category <span class="text-danger">*</span></label>';
|
|
$out .= '<select class="form-select" id="category_id" name="category_id" required>';
|
|
$out .= '<option value="">— select —</option>';
|
|
foreach ($categories as $cat) {
|
|
$v = cry01_h($cat['id'] ?? '');
|
|
$l = cry01_h($cat['label'] ?? $v);
|
|
$out .= '<option value="' . $v . '">' . $l . '</option>';
|
|
}
|
|
$out .= '</select></div>';
|
|
}
|
|
|
|
// Description
|
|
$out .= '<div class="mb-3">';
|
|
$out .= '<label class="form-label" for="capacity_description">Description <span class="text-danger">*</span></label>';
|
|
$out .= '<textarea class="form-control" id="capacity_description" name="capacity_description"
|
|
rows="4" required
|
|
placeholder="Describe what you are offering or seeking in plain language."></textarea>';
|
|
$out .= '</div>';
|
|
|
|
// Denomination
|
|
$out .= '<div class="mb-3">';
|
|
$out .= '<label class="form-label" for="g1_denomination">Ğ1 Amount <span class="text-danger">*</span></label>';
|
|
$out .= '<input type="number" class="form-control" id="g1_denomination" name="g1_denomination"
|
|
required min="1" placeholder="e.g. 100">';
|
|
$out .= '<div class="form-text">The amount in Ğ1 you consider fair exchange.</div>';
|
|
$out .= '</div>';
|
|
|
|
// Duration
|
|
$out .= '<div class="mb-3">';
|
|
$out .= '<label class="form-label" for="duration_days">Duration (days) <span class="text-danger">*</span></label>';
|
|
$out .= '<input type="number" class="form-control" id="duration_days" name="duration_days"
|
|
required min="1" max="365" placeholder="e.g. 14">';
|
|
$out .= '</div>';
|
|
|
|
$out .= '<div class="mt-3">';
|
|
$out .= '<button type="submit" class="btn btn-primary">Register Signal</button>';
|
|
$out .= '</div>';
|
|
$out .= '</form>';
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Ğ1 CERTIFICATION CANDIDATE LIST
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function cry01_render_g1_candidates($association_slug) {
|
|
// Renders the operator-only list of SASE participants with registered Ğ1 keys.
|
|
// TODO: load candidate list from orchestrator spool.
|
|
$out = '<div class="cry01-content">';
|
|
$out .= '<h3>Ğ1 Certification Candidates</h3>';
|
|
$out .= '<p class="text-muted">SASE participants who have registered a Ğ1 public key and are eligible for web of trust certification.</p>';
|
|
$out .= '<p class="text-muted fst-italic">No candidates registered yet.</p>';
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// MANAGE
|
|
// ----------------------------------------------------------------------------
|
|
|
|
function cry01_render_manage($association_slug) {
|
|
// Renders the operator manage page: cache refresh and config status.
|
|
// The Ğ1 public key comes from the wallet session — not from config.
|
|
$cache = cry01_read_cache();
|
|
$refreshed = $cache['refreshed_at'] ?? null;
|
|
$config = cry01_load_config();
|
|
$has_rpc = !empty($config['g1_rpc_endpoint']);
|
|
|
|
$manage_url = z_root() . '/cry01/' . cry01_h($association_slug) . '/manage';
|
|
|
|
$out = '<div class="cry01-content">';
|
|
$out .= '<h3>Value Layer — Manage</h3>';
|
|
|
|
// Config status
|
|
$out .= '<div class="mb-3">';
|
|
$out .= '<h5>Configuration</h5>';
|
|
$out .= '<p>' . ($has_rpc ? '✓' : '✗') . ' Duniter RPC endpoint: ';
|
|
$out .= $has_rpc
|
|
? '<span class="text-success">configured</span>'
|
|
: '<span class="text-danger">missing</span>';
|
|
$out .= '</p>';
|
|
$out .= '<p class="text-muted small">Your Ğ1 public key comes from your Ğ1 Wallet session — not from config. ';
|
|
$out .= 'Unlock your wallet at <a href="' . z_root() . '/g1wallet">Ğ1 Wallet</a>, then return here to refresh.</p>';
|
|
$out .= '</div>';
|
|
|
|
// Cache status
|
|
$out .= '<div class="mb-3">';
|
|
$out .= '<h5>Balance Cache</h5>';
|
|
if ($refreshed) {
|
|
$cached_key = $cache['g1_pubkey'] ?? '';
|
|
$stale = cry01_cache_is_stale() ? ' (stale)' : ' (current)';
|
|
$out .= '<p>Last refreshed: ' . cry01_h($refreshed) . $stale . '</p>';
|
|
if ($cached_key) {
|
|
$out .= '<p class="text-muted small">Cached key: ' . cry01_h(substr($cached_key, 0, 16) . '...') . '</p>';
|
|
}
|
|
} else {
|
|
$out .= '<p class="text-muted">Cache has not been populated yet.</p>';
|
|
}
|
|
$out .= '</div>';
|
|
|
|
// Refresh form — g1_pubkey comes from wallet session via hidden field.
|
|
// g1wallet.js populates data-g1wallet-target="pubkey" fields on unlock.
|
|
$out .= '<form method="post" action="' . $manage_url . '">';
|
|
$out .= cry01_csrf_token();
|
|
$out .= '<input type="hidden" name="action" value="refresh_cache">';
|
|
$out .= '<input type="hidden" name="g1_pubkey" id="manage_g1_pubkey" data-g1wallet-target="pubkey">';
|
|
$out .= '<button type="submit" class="btn btn-sm btn-outline-primary">Refresh Balance Cache</button>';
|
|
$out .= '<span class="text-muted small ms-2">Requires active Ğ1 Wallet session.</span>';
|
|
$out .= '</form>';
|
|
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|