Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 16 additions & 20 deletions dashboard.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
$role = portalGetRole();
$displayName = $user['display_name'] ?? $user['username'] ?? 'User';
$isStaffRole = in_array($role, ['admin', 'staff'], true);
$isAdminRole = $role === 'admin';

$requests = portalLoadProjectRequests();
$proposals = portalLoadProposals();
Expand Down Expand Up @@ -291,6 +292,8 @@
.portal-panel th { color:#5a7a9e;font-size:.68rem;text-transform:uppercase;border-top:none;letter-spacing:.04em; }
.portal-muted { color:#7a9ac0;font-size:.8rem; }
.portal-mono { font-family:monospace;color:#ffc600; }
.portal-primary-action { display:inline-block;border:1px solid rgba(54,243,255,.35);background:rgba(54,243,255,.08);color:#36f3ff;border-radius:4px;padding:2px 8px;font-size:.68rem;font-weight:700;margin-right:7px;text-transform:uppercase;letter-spacing:.04em; }
.portal-primary-action:hover { color:#ffc600;border-color:#ffc600;text-decoration:none; }
.status-chip { display:inline-block;border:1px solid rgba(54,243,255,.28);background:rgba(54,243,255,.08);padding:2px 7px;border-radius:999px;color:#a8bedc;font-size:.68rem;font-weight:700; }
.timeline-list,.message-list { list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px; }
.timeline-list li,.message-list li { border:1px solid rgba(54,243,255,.12);border-radius:8px;padding:9px 10px;background:rgba(5,11,20,.44); }
Expand All @@ -317,6 +320,7 @@
<div class="portal-actions">
<a href="/estimate.php" class="portal-link-btn">Start Project</a>
<?php if ($isStaffRole): ?><a href="/staff/estimate-requests.php" class="portal-link-btn">All Projects</a><?php endif; ?>
<?php if ($isAdminRole): ?><a href="/settings.php" class="portal-link-btn">Settings</a><?php endif; ?>
<a href="/logout.php" class="portal-logout">Sign Out</a>
</div>
</div>
Expand All @@ -338,25 +342,23 @@
<thead>
<tr>
<th>Project ID</th>
<th>Project</th>
<th>Project ID</th>
<th>Client</th>
<th>Status</th>
<th>Updated</th>
<th></th>
</tr>
</thead>
<tbody>
<?php if (empty($recentProjects)): ?>
<tr><td colspan="6" class="portal-muted">No projects yet.</td></tr>
<tr><td colspan="5" class="portal-muted">No projects yet.</td></tr>
<?php else: ?>
<?php foreach ($recentProjects as $project): ?>
<tr>
<td class="portal-mono"><?php echo pe($project['id']); ?></td>
<td class="portal-mono"><a class="portal-primary-action" href="/project.php?id=<?php echo urlencode((string)$project['id']); ?>">Open</a><?php echo pe($project['id']); ?></td>
<td><?php echo pe($project['name']); ?></td>
<td><?php echo pe($project['client']); ?></td>
<td><span class="status-chip"><?php echo pe($project['status_label']); ?></span></td>
<td class="portal-muted"><?php echo $project['last_updated_ts'] > 0 ? pe(date('M j, Y', (int)$project['last_updated_ts'])) : '—'; ?></td>
<td><a href="/project.php?id=<?php echo urlencode((string)$project['id']); ?>" style="color:#36f3ff;">Open</a></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
Expand All @@ -370,23 +372,21 @@
<thead>
<tr>
<th>Project ID</th>
<th>Project</th>
<th>Project ID</th>
<th>Proposal</th>
<th>Agreement</th>
<th></th>
</tr>
</thead>
<tbody>
<?php if (empty($activeProjectRows)): ?>
<tr><td colspan="5" class="portal-muted">No active projects right now.</td></tr>
<tr><td colspan="4" class="portal-muted">No active projects right now.</td></tr>
<?php else: ?>
<?php foreach (array_slice($activeProjectRows, 0, 8) as $project): ?>
<tr>
<td class="portal-mono"><?php echo pe($project['id']); ?></td>
<td class="portal-mono"><a class="portal-primary-action" href="/project.php?id=<?php echo urlencode((string)$project['id']); ?>">Open</a><?php echo pe($project['id']); ?></td>
<td><?php echo pe($project['name']); ?></td>
<td><?php echo pe($project['proposal_status_label']); ?></td>
<td><?php echo pe($project['agreement_status_label']); ?></td>
<td><a href="/project.php?id=<?php echo urlencode((string)$project['id']); ?>" style="color:#36f3ff;">Open</a></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
Expand All @@ -399,24 +399,22 @@
<table>
<thead>
<tr>
<th>Project ID</th>
<th>Project</th>
<th>Project</th>
<th>Status</th>
<th>Created</th>
<th></th>
</tr>
</thead>
<tbody>
<?php if (empty($pendingProjectRows)): ?>
<tr><td colspan="5" class="portal-muted">No pending projects.</td></tr>
<tr><td colspan="4" class="portal-muted">No pending projects.</td></tr>
<?php else: ?>
<?php foreach (array_slice($pendingProjectRows, 0, 8) as $project): ?>
<tr>
<td class="portal-mono"><?php echo pe($project['id']); ?></td>
<td class="portal-mono"><a class="portal-primary-action" href="/project.php?id=<?php echo urlencode((string)$project['id']); ?>">Open</a><?php echo pe($project['id']); ?></td>
<td><?php echo pe($project['name']); ?></td>
<td><span class="status-chip"><?php echo pe($project['status_label']); ?></span></td>
<td class="portal-muted"><?php echo $project['created_ts'] > 0 ? pe(date('M j, Y', (int)$project['created_ts'])) : '—'; ?></td>
<td><a href="/project.php?id=<?php echo urlencode((string)$project['id']); ?>" style="color:#36f3ff;">Open</a></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
Expand All @@ -429,22 +427,20 @@
<table>
<thead>
<tr>
<th>Project ID</th>
<th>Project</th>
<th>Project</th>
<th>Completed</th>
<th></th>
</tr>
</thead>
<tbody>
<?php if (empty($completedProjectRows)): ?>
<tr><td colspan="4" class="portal-muted">No completed projects yet.</td></tr>
<tr><td colspan="3" class="portal-muted">No completed projects yet.</td></tr>
<?php else: ?>
<?php foreach (array_slice($completedProjectRows, 0, 8) as $project): ?>
<tr>
<td class="portal-mono"><?php echo pe($project['id']); ?></td>
<td class="portal-mono"><a class="portal-primary-action" href="/project.php?id=<?php echo urlencode((string)$project['id']); ?>">Open</a><?php echo pe($project['id']); ?></td>
<td><?php echo pe($project['name']); ?></td>
<td class="portal-muted"><?php echo $project['last_updated_ts'] > 0 ? pe(date('M j, Y', (int)$project['last_updated_ts'])) : '—'; ?></td>
<td><a href="/project.php?id=<?php echo urlencode((string)$project['id']); ?>" style="color:#36f3ff;">Open</a></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
Expand Down
64 changes: 64 additions & 0 deletions includes/portal-helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ function portalRefreshVerificationTokenByEmail($email, &$userOut = null) {
define('PORTAL_ESTIMATES_FILE', PORTAL_DATA_DIR . '/estimate_requests.json');
define('PORTAL_PROPOSALS_FILE', PORTAL_DATA_DIR . '/proposals.json');
define('PORTAL_PROJECT_AGREEMENTS_FILE', PORTAL_DATA_DIR . '/project_agreements.json');
define('PORTAL_ADMIN_SETTINGS_FILE', PORTAL_DATA_DIR . '/admin_settings.json');

// Session keys
define('PORTAL_STAFF_SESSION', 'rls_portal_staff');
Expand Down Expand Up @@ -276,6 +277,64 @@ function portalSaveJson($file, $data) {
return file_put_contents($file, $json, LOCK_EX) !== false;
}

function portalDefaultAdminSettings() {
return [
'paypal' => [
'client_id' => '',
'secret' => '',
'environment' => 'sandbox',
'business_email' => '',
'invoice_defaults' => '',
],
'email' => [
'from_name' => '',
'from_email' => '',
'reply_to' => '',
],
'site' => [
'company_name' => 'Runlevel Systems',
'support_email' => '',
'support_phone' => '',
],
'business' => [
'legal_name' => '',
'address' => '',
],
'updated_at' => '',
'updated_by' => '',
];
}

function portalLoadAdminSettings() {
$stored = portalLoadJson(PORTAL_ADMIN_SETTINGS_FILE);
$defaults = portalDefaultAdminSettings();
$paypalStored = isset($stored['paypal']) && is_array($stored['paypal']) ? $stored['paypal'] : [];
$emailStored = isset($stored['email']) && is_array($stored['email']) ? $stored['email'] : [];
$siteStored = isset($stored['site']) && is_array($stored['site']) ? $stored['site'] : [];
$businessStored = isset($stored['business']) && is_array($stored['business']) ? $stored['business'] : [];
return [
'paypal' => array_merge($defaults['paypal'], $paypalStored),
'email' => array_merge($defaults['email'], $emailStored),
'site' => array_merge($defaults['site'], $siteStored),
'business' => array_merge($defaults['business'], $businessStored),
'updated_at' => (string)($stored['updated_at'] ?? ''),
'updated_by' => (string)($stored['updated_by'] ?? ''),
];
}

function portalSaveAdminSettings(array $settings) {
$defaults = portalDefaultAdminSettings();
$payload = [
'paypal' => array_merge($defaults['paypal'], isset($settings['paypal']) && is_array($settings['paypal']) ? $settings['paypal'] : []),
'email' => array_merge($defaults['email'], isset($settings['email']) && is_array($settings['email']) ? $settings['email'] : []),
'site' => array_merge($defaults['site'], isset($settings['site']) && is_array($settings['site']) ? $settings['site'] : []),
'business' => array_merge($defaults['business'], isset($settings['business']) && is_array($settings['business']) ? $settings['business'] : []),
'updated_at' => (string)($settings['updated_at'] ?? ''),
'updated_by' => (string)($settings['updated_by'] ?? ''),
];
return portalSaveJson(PORTAL_ADMIN_SETTINGS_FILE, $payload);
}

/**
* Sanitize HTML output.
*/
Expand Down Expand Up @@ -681,13 +740,18 @@ function portalNormalizeProjectRequest(array $request) {
$request['admin_notes_updated_at'] = (string)($request['admin_notes_updated_at'] ?? '');
$request['client_notes'] = (string)($request['client_notes'] ?? '');
$request['client_notes_updated_at'] = (string)($request['client_notes_updated_at'] ?? '');
$request['staff_response'] = (string)($request['staff_response'] ?? '');
$request['staff_response_updated_at'] = (string)($request['staff_response_updated_at'] ?? '');
$request['invoice_reference'] = (string)($request['invoice_reference'] ?? '');
$request['invoice_status'] = (string)($request['invoice_status'] ?? '');
$request['amount_due'] = (string)($request['amount_due'] ?? '');
$request['amount_paid'] = (string)($request['amount_paid'] ?? '');
$request['balance_due'] = (string)($request['balance_due'] ?? '');
$request['payment_notes'] = (string)($request['payment_notes'] ?? '');
$request['payment_received_at'] = (string)($request['payment_received_at'] ?? '');
$request['payment_link'] = (string)($request['payment_link'] ?? '');
$request['invoice_sent_at'] = (string)($request['invoice_sent_at'] ?? '');
$request['attachments'] = isset($request['attachments']) && is_array($request['attachments']) ? array_values($request['attachments']) : [];
$request['proposal_ids'] = isset($request['proposal_ids']) && is_array($request['proposal_ids']) ? array_values($request['proposal_ids']) : [];
$request['agreement_ids'] = isset($request['agreement_ids']) && is_array($request['agreement_ids']) ? array_values($request['agreement_ids']) : [];
if (!isset($request['created_at']) || trim((string)$request['created_at']) === '') {
Expand Down
Loading
Loading