Initial push

This commit is contained in:
2026-06-08 02:08:51 -04:00
parent e540094df2
commit c6fdd38612
4 changed files with 770 additions and 0 deletions

View File

@@ -0,0 +1,245 @@
<?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>';
$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 operator Ğ1 balance from cache. Shows staleness if cache is old.
$cache = cry01_read_cache();
$balance = $cache['operator_balance'] ?? null;
$pubkey = $cache['operator_g1_pubkey'] ?? '';
$refreshed = $cache['refreshed_at'] ?? null;
$out = '<div class="cry01-balance-display mb-4">';
$out .= '<h5 class="cry01-section-label">Operator Ğ1 Balance</h5>';
if ($balance === null) {
$out .= '<p class="text-muted fst-italic">Balance not yet loaded. Operator: 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.
// Placeholder until orchestrator query is implemented.
$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.
$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>';
$out .= '<form method="post" action="' . $form_url . '" class="cry01-form" novalidate>';
$out .= cry01_csrf_token();
// Ğ1 public key
$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">';
$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.
$cache = cry01_read_cache();
$refreshed = $cache['refreshed_at'] ?? null;
$config = cry01_load_config();
$has_rpc = !empty($config['g1_rpc_endpoint']);
$has_key = !empty($config['operator_g1_pubkey']);
$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>' . ($has_key ? '✓' : '✗') . ' Operator Ğ1 public key: ';
$out .= $has_key ? '<span class="text-success">configured</span>' : '<span class="text-danger">missing</span>';
$out .= '</p>';
$out .= '</div>';
// Cache status
$out .= '<div class="mb-3">';
$out .= '<h5>Balance Cache</h5>';
if ($refreshed) {
$stale = cry01_cache_is_stale() ? ' (stale)' : ' (current)';
$out .= '<p>Last refreshed: ' . cry01_h($refreshed) . $stale . '</p>';
} else {
$out .= '<p class="text-muted">Cache has not been populated yet.</p>';
}
$out .= '</div>';
// Refresh form
$out .= '<form method="post" action="' . $manage_url . '">';
$out .= cry01_csrf_token();
$out .= '<input type="hidden" name="action" value="refresh_cache">';
$out .= '<button type="submit" class="btn btn-sm btn-outline-primary">Refresh Balance Cache</button>';
$out .= '</form>';
$out .= '</div>';
return $out;
}