203 lines
7.8 KiB
PHP
203 lines
7.8 KiB
PHP
<?php
|
|
|
|
/**
|
|
* DSC-01 Renderer
|
|
* Renders the ten DSC category checklist. See DSC-RENDERER-SPEC.md.
|
|
*/
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SCHEMA LOADING
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function dsc01_load_categories() {
|
|
$dir = 'addon/dsc01/diagnostic-categories';
|
|
$out = [];
|
|
$files = @glob($dir . '/DSC-*.json');
|
|
if (!$files) return $out;
|
|
sort($files);
|
|
foreach ($files as $file) {
|
|
$raw = @file_get_contents($file);
|
|
if ($raw === false) continue;
|
|
$data = json_decode($raw, true);
|
|
if (json_last_error() !== JSON_ERROR_NONE) continue;
|
|
$meta = $data['_meta'] ?? null;
|
|
if (!$meta || empty($meta['code'])) continue;
|
|
$out[$meta['code']] = $meta;
|
|
}
|
|
ksort($out);
|
|
return $out;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// RENDER — INDEX (category overview)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function dsc01_render_index() {
|
|
$categories = dsc01_load_categories();
|
|
|
|
$out = '<div class="dsc01-content">';
|
|
$out .= '<div class="dsc01-header mb-3">';
|
|
$out .= '<h2>Diagnostic Surface Categories</h2>';
|
|
$out .= '<p class="text-muted">The legal surfaces where HOA governance disputes manifest, organized from the homeowner\'s perspective. Select an association to apply this checklist to a case.</p>';
|
|
$out .= '</div>';
|
|
|
|
if (empty($categories)) {
|
|
$out .= '<div class="dsc01-placeholder text-muted fst-italic">No categories defined.</div>';
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
$out .= '<nav class="dsc01-category-nav" aria-label="Diagnostic Surface Categories">';
|
|
$out .= '<ul class="list-group list-group-flush">';
|
|
foreach ($categories as $code => $meta) {
|
|
$title = dsc01_h($meta['title'] ?? $code);
|
|
$summary = dsc01_h($meta['summary'] ?? '');
|
|
$out .= '<li class="list-group-item">';
|
|
$out .= '<strong>' . dsc01_h($code) . '</strong> — ' . $title;
|
|
if ($summary) {
|
|
$out .= '<p class="small text-muted mb-0">' . $summary . '</p>';
|
|
}
|
|
$out .= '</li>';
|
|
}
|
|
$out .= '</ul></nav>';
|
|
|
|
// Association picker — list associations from vs01/config.json
|
|
$raw = @file_get_contents('addon/vs01/config.json');
|
|
$cfg = $raw ? json_decode($raw, true) : [];
|
|
$associations = $cfg['associations'] ?? [];
|
|
|
|
if (!empty($associations)) {
|
|
$out .= '<div class="dsc01-association-picker mt-4">';
|
|
$out .= '<h3>Apply this checklist</h3>';
|
|
$out .= '<ul class="list-group">';
|
|
foreach ($associations as $slug => $assoc) {
|
|
$name = dsc01_h($assoc['name'] ?? $slug);
|
|
$url = z_root() . '/dsc01/' . dsc01_h($slug);
|
|
$out .= '<li class="list-group-item"><a href="' . $url . '">' . $name . '</a></li>';
|
|
}
|
|
$out .= '</ul></div>';
|
|
}
|
|
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// RENDER — ASSOCIATION LANDING (checklist form)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function dsc01_render_landing($association_slug, $access, $submitted_codes = [], $submitted_narrative = '') {
|
|
$raw = @file_get_contents('addon/vs01/config.json');
|
|
$cfg = $raw ? json_decode($raw, true) : [];
|
|
$assoc = $cfg['associations'][$association_slug] ?? [];
|
|
$name = dsc01_h($assoc['name'] ?? $association_slug);
|
|
|
|
$categories = dsc01_load_categories();
|
|
|
|
$out = '<div class="dsc01-content">';
|
|
$out .= '<div class="dsc01-header mb-3">';
|
|
$out .= '<h2>' . $name . '</h2>';
|
|
$out .= '<p class="text-muted">Diagnostic Surface Categories checklist. Select every category that applies to your situation.</p>';
|
|
$out .= '</div>';
|
|
|
|
if ($access === 'public') {
|
|
$out .= dsc01_render_checklist_readonly($categories);
|
|
$out .= '<div class="alert alert-info mt-3">';
|
|
$out .= 'DSC Categories are public. ';
|
|
$out .= '<a href="https://directory.diagnostics.kane-il.us/channel/theron">Complete the SASE process</a> ';
|
|
$out .= 'to submit a checklist for this association.';
|
|
$out .= '</div>';
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
$form_url = z_root() . '/dsc01/' . dsc01_h($association_slug);
|
|
|
|
$out .= '<form method="post" action="' . $form_url . '" class="dsc01-form" novalidate>';
|
|
$out .= dsc01_csrf_token();
|
|
|
|
foreach ($categories as $code => $meta) {
|
|
$checked = in_array($code, $submitted_codes, true) ? ' checked' : '';
|
|
$title = dsc01_h($meta['title'] ?? $code);
|
|
|
|
$out .= '<div class="dsc01-category">';
|
|
$out .= '<label class="dsc01-category-label">';
|
|
$out .= '<input type="checkbox" name="dsc_codes[]" value="' . dsc01_h($code) . '"' . $checked . '> ';
|
|
$out .= '<strong>' . dsc01_h($code) . '</strong> — ' . $title;
|
|
$out .= '</label>';
|
|
|
|
if (!empty($meta['diagnostic_questions'])) {
|
|
$out .= '<details class="dsc01-questions">';
|
|
$out .= '<summary>Diagnostic questions</summary>';
|
|
$out .= '<ul>';
|
|
foreach ($meta['diagnostic_questions'] as $q) {
|
|
$out .= '<li>' . dsc01_h($q) . '</li>';
|
|
}
|
|
$out .= '</ul>';
|
|
$out .= '</details>';
|
|
}
|
|
|
|
$out .= '</div>';
|
|
}
|
|
|
|
$out .= '<div class="dsc01-narrative mt-3">';
|
|
$out .= '<label for="dsc01_narrative"><strong>Describe your situation</strong></label>';
|
|
$out .= '<p class="small text-muted mb-1">Please keep your description focused on the categories you selected above.</p>';
|
|
$out .= '<textarea id="dsc01_narrative" name="narrative" class="form-control" rows="6" placeholder="Describe how the categories you checked above apply to your situation.">'
|
|
. dsc01_h($submitted_narrative) . '</textarea>';
|
|
$out .= '</div>';
|
|
|
|
$out .= '<div class="mt-3">';
|
|
$out .= '<button type="submit" class="btn btn-primary">Submit</button>';
|
|
$out .= '</div>';
|
|
$out .= '</form>';
|
|
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// RENDER — READ-ONLY CHECKLIST (public access)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function dsc01_render_checklist_readonly($categories) {
|
|
$out = '<div class="dsc01-checklist-readonly">';
|
|
foreach ($categories as $code => $meta) {
|
|
$title = dsc01_h($meta['title'] ?? $code);
|
|
$out .= '<div class="dsc01-category">';
|
|
$out .= '<strong>' . dsc01_h($code) . '</strong> — ' . $title;
|
|
|
|
if (!empty($meta['diagnostic_questions'])) {
|
|
$out .= '<details class="dsc01-questions">';
|
|
$out .= '<summary>Diagnostic questions</summary>';
|
|
$out .= '<ul>';
|
|
foreach ($meta['diagnostic_questions'] as $q) {
|
|
$out .= '<li>' . dsc01_h($q) . '</li>';
|
|
}
|
|
$out .= '</ul>';
|
|
$out .= '</details>';
|
|
}
|
|
|
|
$out .= '</div>';
|
|
}
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// RENDER — MANAGE (stub, operator only)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function dsc01_render_manage($association_slug) {
|
|
$raw = @file_get_contents('addon/vs01/config.json');
|
|
$cfg = $raw ? json_decode($raw, true) : [];
|
|
$assoc = $cfg['associations'][$association_slug] ?? [];
|
|
$name = dsc01_h($assoc['name'] ?? $association_slug);
|
|
|
|
$out = '<div class="dsc01-content">';
|
|
$out .= '<h2>Manage — ' . $name . '</h2>';
|
|
$out .= '<p class="text-muted fst-italic">DSC record review forthcoming.</p>';
|
|
$out .= '</div>';
|
|
return $out;
|
|
}
|