Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70a9003080 | ||
|
|
fd9ccfc89a |
216
add_client.php
Normal file
216
add_client.php
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
|
||||||
|
$required_fields = ['full_legal_name'];
|
||||||
|
foreach ($required_fields as $field) {
|
||||||
|
if (empty($_POST[$field])) {
|
||||||
|
throw new Exception("'$field' is a required field.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "INSERT INTO clients (
|
||||||
|
full_legal_name, ndis_client_number, date_of_birth, preferred_contact_method,
|
||||||
|
primary_phone, email, address, emergency_contact_name, emergency_contact_phone,
|
||||||
|
ndis_plan_start_date, ndis_plan_end_date, plan_manager_name, plan_manager_contact,
|
||||||
|
ndis_funding_budget_total, primary_disability, support_needs_summary,
|
||||||
|
communication_aids_methods, behaviours_of_concern, risk_assessment_summary,
|
||||||
|
safety_plan, consent_for_info_sharing, intake_notes
|
||||||
|
) VALUES (
|
||||||
|
:full_legal_name, :ndis_client_number, :date_of_birth, :preferred_contact_method,
|
||||||
|
:primary_phone, :email, :address, :emergency_contact_name, :emergency_contact_phone,
|
||||||
|
:ndis_plan_start_date, :ndis_plan_end_date, :plan_manager_name, :plan_manager_contact,
|
||||||
|
:ndis_funding_budget_total, :primary_disability, :support_needs_summary,
|
||||||
|
:communication_aids_methods, :behaviours_of_concern, :risk_assessment_summary,
|
||||||
|
:safety_plan, :consent_for_info_sharing, :intake_notes
|
||||||
|
)";
|
||||||
|
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
|
||||||
|
$consent = isset($_POST['consent_for_info_sharing']) ? 1 : 0;
|
||||||
|
|
||||||
|
$stmt->bindParam(':full_legal_name', $_POST['full_legal_name']);
|
||||||
|
$stmt->bindParam(':ndis_client_number', $_POST['ndis_client_number']);
|
||||||
|
$stmt->bindParam(':date_of_birth', $_POST['date_of_birth']);
|
||||||
|
$stmt->bindParam(':preferred_contact_method', $_POST['preferred_contact_method']);
|
||||||
|
$stmt->bindParam(':primary_phone', $_POST['primary_phone']);
|
||||||
|
$stmt->bindParam(':email', $_POST['email']);
|
||||||
|
$stmt->bindParam(':address', $_POST['address']);
|
||||||
|
$stmt->bindParam(':emergency_contact_name', $_POST['emergency_contact_name']);
|
||||||
|
$stmt->bindParam(':emergency_contact_phone', $_POST['emergency_contact_phone']);
|
||||||
|
$stmt->bindParam(':ndis_plan_start_date', $_POST['ndis_plan_start_date']);
|
||||||
|
$stmt->bindParam(':ndis_plan_end_date', $_POST['ndis_plan_end_date']);
|
||||||
|
$stmt->bindParam(':plan_manager_name', $_POST['plan_manager_name']);
|
||||||
|
$stmt->bindParam(':plan_manager_contact', $_POST['plan_manager_contact']);
|
||||||
|
$stmt->bindParam(':ndis_funding_budget_total', $_POST['ndis_funding_budget_total']);
|
||||||
|
$stmt->bindParam(':primary_disability', $_POST['primary_disability']);
|
||||||
|
$stmt->bindParam(':support_needs_summary', $_POST['support_needs_summary']);
|
||||||
|
$stmt->bindParam(':communication_aids_methods', $_POST['communication_aids_methods']);
|
||||||
|
$stmt->bindParam(':behaviours_of_concern', $_POST['behaviours_of_concern']);
|
||||||
|
$stmt->bindParam(':risk_assessment_summary', $_POST['risk_assessment_summary']);
|
||||||
|
$stmt->bindParam(':safety_plan', $_POST['safety_plan']);
|
||||||
|
$stmt->bindParam(':consent_for_info_sharing', $consent, PDO::PARAM_INT);
|
||||||
|
$stmt->bindParam(':intake_notes', $_POST['intake_notes']);
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$message = "Client successfully added!";
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = "Error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
|
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; }
|
||||||
|
.form-section { background-color: #fdfdfd; padding: 1.5rem; border-radius: 8px; border: 1px solid #eee; }
|
||||||
|
.form-section h3 { font-size: 1.2rem; margin-bottom: 1.5rem; border-bottom: 1px solid #eee; padding-bottom: 1rem; }
|
||||||
|
.ai-section { background-color: #eaf5ff; padding: 1.5rem; border-radius: 8px; margin-bottom: 2rem; border: 1px solid #c7dfff; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Add New Client</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="feedback success"><?php echo $message; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="feedback error"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="add_client.php" method="POST">
|
||||||
|
<div class="ai-section">
|
||||||
|
<h3>AI-Assisted Intake</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="intake_notes">Raw Intake Notes</label>
|
||||||
|
<textarea id="intake_notes" name="intake_notes" rows="6" placeholder="Paste the full, unstructured intake notes here..."></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-secondary" id="summarize-with-ai">Summarize with AI</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-grid">
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Client Details</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="full_legal_name">Full Legal Name *</label>
|
||||||
|
<input type="text" id="full_legal_name" name="full_legal_name" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_client_number">NDIS Client Number</label>
|
||||||
|
<input type="text" id="ndis_client_number" name="ndis_client_number">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="date_of_birth">Date of Birth</label>
|
||||||
|
<input type="date" id="date_of_birth" name="date_of_birth">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="preferred_contact_method">Preferred Contact Method</label>
|
||||||
|
<input type="text" id="preferred_contact_method" name="preferred_contact_method">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Contact Info</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="primary_phone">Primary Phone</label>
|
||||||
|
<input type="tel" id="primary_phone" name="primary_phone">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email">Email</label>
|
||||||
|
<input type="email" id="email" name="email">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="address">Address</label>
|
||||||
|
<textarea id="address" name="address" rows="1"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="emergency_contact_name">Emergency Contact Name</label>
|
||||||
|
<input type="text" id="emergency_contact_name" name="emergency_contact_name">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="emergency_contact_phone">Emergency Contact Phone</label>
|
||||||
|
<input type="tel" id="emergency_contact_phone" name="emergency_contact_phone">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Plan Details</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_plan_start_date">NDIS Plan Start Date</label>
|
||||||
|
<input type="date" id="ndis_plan_start_date" name="ndis_plan_start_date">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_plan_end_date">NDIS Plan End Date</label>
|
||||||
|
<input type="date" id="ndis_plan_end_date" name="ndis_plan_end_date">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="plan_manager_name">Plan Manager Name</label>
|
||||||
|
<input type="text" id="plan_manager_name" name="plan_manager_name">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="plan_manager_contact">Plan Manager Contact</label>
|
||||||
|
<input type="text" id="plan_manager_contact" name="plan_manager_contact">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_funding_budget_total">NDIS Funding Budget (Total)</label>
|
||||||
|
<input type="number" step="0.01" id="ndis_funding_budget_total" name="ndis_funding_budget_total">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Disability & Needs</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="primary_disability">Primary Disability</label>
|
||||||
|
<textarea id="primary_disability" name="primary_disability" rows="2"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="support_needs_summary">Support Needs Summary</label>
|
||||||
|
<textarea id="support_needs_summary" name="support_needs_summary" rows="2"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="communication_aids_methods">Communication Aids/Methods</label>
|
||||||
|
<textarea id="communication_aids_methods" name="communication_aids_methods" rows="2"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Risk & Safety</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="behaviours_of_concern">Known Behaviours of Concern</label>
|
||||||
|
<textarea id="behaviours_of_concern" name="behaviours_of_concern" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="risk_assessment_summary">Detailed Risk Assessment Summary</label>
|
||||||
|
<textarea id="risk_assessment_summary" name="risk_assessment_summary" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="safety_plan">Safety/Restrictive Practices Plan</label>
|
||||||
|
<textarea id="safety_plan" name="safety_plan" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Consent</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="checkbox" id="consent_for_info_sharing" name="consent_for_info_sharing" value="1" style="width: auto; margin-right: 10px;">
|
||||||
|
<label for="consent_for_info_sharing">Consent for information sharing has been recorded.</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 2rem;">
|
||||||
|
<button type="submit" class="btn btn-primary">Add Client</button>
|
||||||
|
<a href="clients.php" class="btn btn-secondary">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
94
add_staff.php
Normal file
94
add_staff.php
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
|
||||||
|
if (empty($_POST['full_name'])) {
|
||||||
|
throw new Exception("Full Name is a required field.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "INSERT INTO care_staff (
|
||||||
|
full_name, contact_info, ndis_worker_screening_number,
|
||||||
|
ndis_worker_screening_expiry, first_aid_expiry, qualifications, hourly_rate
|
||||||
|
) VALUES (
|
||||||
|
:full_name, :contact_info, :ndis_worker_screening_number,
|
||||||
|
:ndis_worker_screening_expiry, :first_aid_expiry, :qualifications, :hourly_rate
|
||||||
|
)";
|
||||||
|
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
|
||||||
|
$stmt->bindParam(':full_name', $_POST['full_name']);
|
||||||
|
$stmt->bindParam(':contact_info', $_POST['contact_info']);
|
||||||
|
$stmt->bindParam(':ndis_worker_screening_number', $_POST['ndis_worker_screening_number']);
|
||||||
|
$stmt->bindParam(':ndis_worker_screening_expiry', $_POST['ndis_worker_screening_expiry']);
|
||||||
|
$stmt->bindParam(':first_aid_expiry', $_POST['first_aid_expiry']);
|
||||||
|
$stmt->bindParam(':qualifications', $_POST['qualifications']);
|
||||||
|
$stmt->bindParam(':hourly_rate', $_POST['hourly_rate']);
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$message = "Care staff member successfully added!";
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = "Error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Add New Staff Member</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="feedback success"><?php echo $message; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="feedback error"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="add_staff.php" method="POST">
|
||||||
|
<div class="form-grid" style="grid-template-columns: 1fr;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="full_name">Full Name *</label>
|
||||||
|
<input type="text" id="full_name" name="full_name" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="contact_info">Contact Info (Phone/Email)</label>
|
||||||
|
<textarea id="contact_info" name="contact_info" rows="2"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="qualifications">Qualifications/Certificates</label>
|
||||||
|
<textarea id="qualifications" name="qualifications" rows="3"></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_worker_screening_number">NDIS Staff Screening Check Number</label>
|
||||||
|
<input type="text" id="ndis_worker_screening_number" name="ndis_worker_screening_number">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_worker_screening_expiry">Screening Check Expiry Date</label>
|
||||||
|
<input type="date" id="ndis_worker_screening_expiry" name="ndis_worker_screening_expiry">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="first_aid_expiry">First Aid Certificate Expiry Date</label>
|
||||||
|
<input type="date" id="first_aid_expiry" name="first_aid_expiry">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="hourly_rate">Hourly Rate</label>
|
||||||
|
<input type="number" step="0.01" id="hourly_rate" name="hourly_rate">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 2rem;">
|
||||||
|
<button type="submit" class="btn btn-primary">Add Staff Member</button>
|
||||||
|
<a href="care_staff.php" class="btn">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
55
api/summarize_notes.php
Normal file
55
api/summarize_notes.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
require_once __DIR__ . '/../ai/LocalAIApi.php';
|
||||||
|
|
||||||
|
$input = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
if (empty($input['notes'])) {
|
||||||
|
echo json_encode(['error' => 'No notes provided.']);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notes = $input['notes'];
|
||||||
|
|
||||||
|
$prompt = <<<PROMPT
|
||||||
|
You are an expert NDIS support coordinator. A new participant's initial intake notes are provided below.
|
||||||
|
|
||||||
|
Your tasks are:
|
||||||
|
1. Summarize the participant's primary disability and support needs into a concise paragraph. This will be used for the "Support Needs Summary" field.
|
||||||
|
2. Based on the summary, extract any specific communication aids or methods mentioned (e.g., uses Auslan, requires a translator, non-verbal). This will be for the "Communication Aids/Methods" field.
|
||||||
|
3. Based on the summary, identify any mentioned "Behaviours of Concern" and list them.
|
||||||
|
|
||||||
|
Return the output as a JSON object with the following keys: "support_needs_summary", "communication_aids_methods", "behaviours_of_concern".
|
||||||
|
|
||||||
|
---
|
||||||
|
INTAKE NOTES:
|
||||||
|
{$notes}
|
||||||
|
---
|
||||||
|
PROMPT;
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
$resp = LocalAIApi::createResponse([
|
||||||
|
'input' => [
|
||||||
|
['role' => 'system', 'content' => $prompt],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!empty($resp['success'])) {
|
||||||
|
$text = LocalAIApi::extractText($resp);
|
||||||
|
$json_output = LocalAIApi::decodeJsonFromResponse($resp);
|
||||||
|
|
||||||
|
if ($json_output) {
|
||||||
|
echo json_encode($json_output);
|
||||||
|
} else {
|
||||||
|
// If the model didn't return valid JSON, try to wrap its text output in a JSON structure.
|
||||||
|
echo json_encode(['support_needs_summary' => $text]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception($resp['error'] ?? 'Unknown AI error');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(['error' => 'AI Service Error: ' . $e->getMessage()]);
|
||||||
|
}
|
||||||
340
assets/css/style.css
Normal file
340
assets/css/style.css
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
/* General Styles */
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--primary-color: #0A2240; /* Navy Blue */
|
||||||
|
--secondary-color: #F0F2F5; /* Soft Grey */
|
||||||
|
--accent-color: #48E5C2; /* Teal */
|
||||||
|
--text-color: #333333;
|
||||||
|
--text-secondary-color: #6c757d;
|
||||||
|
--background-color: #F8F9FA;
|
||||||
|
--surface-color: #FFFFFF;
|
||||||
|
--border-color: #E9ECEF;
|
||||||
|
--danger-color: #e74c3c;
|
||||||
|
|
||||||
|
--font-family-sans-serif: 'Inter', sans-serif;
|
||||||
|
|
||||||
|
--space-1: 4px;
|
||||||
|
--space-2: 8px;
|
||||||
|
--space-3: 12px;
|
||||||
|
--space-4: 16px;
|
||||||
|
--space-5: 24px;
|
||||||
|
--space-6: 32px;
|
||||||
|
--space-7: 48px;
|
||||||
|
--space-8: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: var(--font-family-sans-serif);
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
display: flex;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: var(--accent-color);
|
||||||
|
transition: color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: #36c1a2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sidebar Navigation */
|
||||||
|
.sidebar {
|
||||||
|
width: 240px;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
padding: var(--space-5);
|
||||||
|
position: fixed;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: var(--secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .logo {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: var(--space-6);
|
||||||
|
color: var(--surface-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar nav a {
|
||||||
|
display: block;
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
border-radius: var(--space-1);
|
||||||
|
color: var(--secondary-color);
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background-color 0.2s ease, color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar nav a:hover,
|
||||||
|
.sidebar nav a.active {
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
color: var(--surface-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar .footer {
|
||||||
|
margin-top: auto;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #a0a8b3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Main Content Area */
|
||||||
|
.main-content {
|
||||||
|
margin-left: 240px;
|
||||||
|
flex-grow: 1;
|
||||||
|
padding: var(--space-6);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: var(--space-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content header h1 {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buttons */
|
||||||
|
.btn,
|
||||||
|
button,
|
||||||
|
input[type="submit"] {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
color: var(--primary-color);
|
||||||
|
padding: var(--space-3) var(--space-5);
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--space-2);
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: var(--font-family-sans-serif);
|
||||||
|
font-weight: 600;
|
||||||
|
transition: background-color 0.3s ease, transform 0.2s ease;
|
||||||
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover,
|
||||||
|
button:hover,
|
||||||
|
input[type="submit"]:hover {
|
||||||
|
background-color: #36c1a2;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: var(--surface-color);
|
||||||
|
}
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #081b33;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
color: var(--text-color);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background-color: #e2e6ea;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger {
|
||||||
|
background-color: var(--danger-color);
|
||||||
|
color: var(--surface-color);
|
||||||
|
}
|
||||||
|
.btn-danger:hover {
|
||||||
|
background-color: #c0392b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Info Cards (Dashboard) & Data Cards (Lists) */
|
||||||
|
.card-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: var(--space-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background-color: var(--surface-color);
|
||||||
|
border-radius: var(--space-2);
|
||||||
|
padding: var(--space-5);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
margin-bottom: var(--space-4);
|
||||||
|
padding-bottom: var(--space-3);
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header h3 {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body p {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--primary-color);
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-footer {
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-footer a {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: var(--space-1) var(--space-2);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: var(--space-1);
|
||||||
|
color: var(--surface-color);
|
||||||
|
}
|
||||||
|
.status-tag.active { background-color: #2ecc71; }
|
||||||
|
.status-tag.inactive { background-color: var(--text-secondary-color); }
|
||||||
|
.status-tag.expiring { background-color: #f39c12; }
|
||||||
|
.status-tag.unbilled { background-color: var(--danger-color); }
|
||||||
|
|
||||||
|
|
||||||
|
/* Forms */
|
||||||
|
form {
|
||||||
|
background-color: var(--surface-color);
|
||||||
|
padding: var(--space-6);
|
||||||
|
border-radius: var(--space-2);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: var(--space-2);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input,
|
||||||
|
.form-group select,
|
||||||
|
.form-group textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: var(--space-3);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: var(--space-2);
|
||||||
|
font-family: var(--font-family-sans-serif);
|
||||||
|
background-color: var(--background-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input:focus,
|
||||||
|
.form-group select:focus,
|
||||||
|
.form-group textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
box-shadow: 0 0 0 3px rgba(72, 229, 194, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detail Views */
|
||||||
|
.detail-container {
|
||||||
|
background-color: var(--surface-color);
|
||||||
|
padding: var(--space-6);
|
||||||
|
border-radius: var(--space-2);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.04);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-actions {
|
||||||
|
margin-top: var(--space-5);
|
||||||
|
display: flex;
|
||||||
|
gap: var(--space-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables (legacy, for reference) */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
background-color: var(--surface-color);
|
||||||
|
border-radius: var(--space-2);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: var(--space-4);
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
tbody tr:last-child td { border-bottom: none; }
|
||||||
|
tbody tr:hover { background-color: #fcfcfd; }
|
||||||
|
|
||||||
|
/* Empty States */
|
||||||
|
.empty-state {
|
||||||
|
text-align: center;
|
||||||
|
padding: var(--space-8) var(--space-5);
|
||||||
|
background-color: var(--surface-color);
|
||||||
|
border: 2px dashed var(--border-color);
|
||||||
|
border-radius: var(--space-2);
|
||||||
|
}
|
||||||
|
.empty-state h3 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
margin-bottom: var(--space-3);
|
||||||
|
}
|
||||||
|
.empty-state p {
|
||||||
|
color: var(--text-secondary-color);
|
||||||
|
margin-bottom: var(--space-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Charts */
|
||||||
|
.charts-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||||
|
gap: var(--space-5);
|
||||||
|
margin-top: var(--space-5);
|
||||||
|
}
|
||||||
|
.chart-card {
|
||||||
|
background-color: var(--surface-color);
|
||||||
|
border-radius: var(--space-2);
|
||||||
|
padding: var(--space-5);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.04);
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
.chart-card h3 {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: var(--space-4);
|
||||||
|
}
|
||||||
69
assets/js/main.js
Normal file
69
assets/js/main.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const summarizeBtn = document.getElementById('summarize-with-ai');
|
||||||
|
const intakeNotes = document.getElementById('intake_notes');
|
||||||
|
|
||||||
|
if (summarizeBtn && intakeNotes) {
|
||||||
|
summarizeBtn.addEventListener('click', async () => {
|
||||||
|
const notes = intakeNotes.value;
|
||||||
|
if (!notes.trim()) {
|
||||||
|
alert('Please enter some intake notes first.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
summarizeBtn.disabled = true;
|
||||||
|
summarizeBtn.innerHTML = 'Summarizing...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch('api/summarize_notes.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ notes: notes })
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.error) {
|
||||||
|
throw new Error(data.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.summary) {
|
||||||
|
// This is a simple example. We'll populate fields based on a hypothetical structured response.
|
||||||
|
// A real implementation would need to parse the summary more intelligently.
|
||||||
|
const summary = data.summary;
|
||||||
|
|
||||||
|
// Example of populating fields:
|
||||||
|
if (summary.full_legal_name) {
|
||||||
|
document.getElementById('full_legal_name').value = summary.full_legal_name;
|
||||||
|
}
|
||||||
|
if (summary.email) {
|
||||||
|
document.getElementById('email').value = summary.email;
|
||||||
|
}
|
||||||
|
if (summary.primary_phone) {
|
||||||
|
document.getElementById('primary_phone').value = summary.primary_phone;
|
||||||
|
}
|
||||||
|
if (summary.primary_disability) {
|
||||||
|
document.getElementById('primary_disability').value = summary.primary_disability;
|
||||||
|
}
|
||||||
|
if (summary.support_needs_summary) {
|
||||||
|
document.getElementById('support_needs_summary').value = summary.support_needs_summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
alert('AI summarization complete. Please review the populated fields.');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('AI Summarization Error:', error);
|
||||||
|
alert('An error occurred while summarizing the notes. Please check the console.');
|
||||||
|
} finally {
|
||||||
|
summarizeBtn.disabled = false;
|
||||||
|
summarizeBtn.innerHTML = 'Summarize with AI';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
99
bookings.php
Normal file
99
bookings.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$bookings = [];
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$sql = "SELECT
|
||||||
|
sl.id,
|
||||||
|
sl.service_date,
|
||||||
|
p.full_legal_name AS client_name,
|
||||||
|
w.full_name AS staff_name,
|
||||||
|
sl.ndis_line_item,
|
||||||
|
sl.duration_minutes,
|
||||||
|
sl.billing_status
|
||||||
|
FROM
|
||||||
|
bookings sl
|
||||||
|
JOIN
|
||||||
|
clients p ON sl.client_id = p.id
|
||||||
|
JOIN
|
||||||
|
care_staff w ON sl.staff_id = w.id
|
||||||
|
ORDER BY
|
||||||
|
sl.service_date DESC";
|
||||||
|
$stmt = $db->query($sql);
|
||||||
|
$bookings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo '<div class="feedback error">Error: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_status_chip_class($status) {
|
||||||
|
switch ($status) {
|
||||||
|
case 'Paid':
|
||||||
|
return 'status-paid';
|
||||||
|
case 'Billed':
|
||||||
|
return 'status-billed';
|
||||||
|
case 'Pending':
|
||||||
|
default:
|
||||||
|
return 'status-pending';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.status-chip {
|
||||||
|
padding: 0.3rem 0.8rem;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
display: inline-block;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.status-paid { background-color: #2ecc71; }
|
||||||
|
.status-billed { background-color: #f1c40f; color: #333; }
|
||||||
|
.status-pending { background-color: #95a5a6; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Bookings</h1>
|
||||||
|
<a href="log_booking.php" class="btn btn-primary">Log New Booking</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Service Date</th>
|
||||||
|
<th>Client</th>
|
||||||
|
<th>Care Staff</th>
|
||||||
|
<th>Duration (mins)</th>
|
||||||
|
<th>NDIS Line Item</th>
|
||||||
|
<th>Billing Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($bookings)):
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" style="text-align: center;">No bookings found.</td>
|
||||||
|
</tr>
|
||||||
|
<?php else:
|
||||||
|
<?php foreach ($bookings as $log):
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars(date('d M Y, H:i', strtotime($log['service_date']))); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($log['client_name']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($log['staff_name']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($log['duration_minutes']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($log['ndis_line_item']); ?></td>
|
||||||
|
<td>
|
||||||
|
<span class="status-chip <?php echo get_status_chip_class($log['billing_status']); ?>">
|
||||||
|
<?php echo htmlspecialchars($log['billing_status']); ?>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
50
care_staff.php
Normal file
50
care_staff.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$care_staff = [];
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$stmt = $db->query("SELECT id, full_name, ndis_worker_screening_number, first_aid_expiry FROM care_staff ORDER BY created_at DESC");
|
||||||
|
$care_staff = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo '<div class="feedback error">Error: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Care Staff</h1>
|
||||||
|
<a href="add_staff.php" class="btn btn-primary">Add New Staff Member</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Screening Number</th>
|
||||||
|
<th>First Aid Expiry</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($care_staff)):
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" style="text-align: center;">No care staff found.</td>
|
||||||
|
</tr>
|
||||||
|
<?php else:
|
||||||
|
<?php foreach ($care_staff as $w):
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars($w['full_name']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($w['ndis_worker_screening_number']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars(date("d M Y", strtotime($w['first_aid_expiry']))); ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="staff_detail.php?id=<?php echo $w['id']; ?>" class="btn">View</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
113
client_detail.php
Normal file
113
client_detail.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) || !filter_var($_GET['id'], FILTER_VALIDATE_INT)) {
|
||||||
|
echo '<div class="feedback error">Invalid client ID.</div>';
|
||||||
|
require_once 'footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$client_id = $_GET['id'];
|
||||||
|
$client = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$stmt = $db->prepare("SELECT * FROM clients WHERE id = :id");
|
||||||
|
$stmt->bindParam(':id', $client_id, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$client = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo '<div class="feedback error">Error: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$client) {
|
||||||
|
echo '<div class="feedback error">Client not found.</div>';
|
||||||
|
require_once 'footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_detail_item($label, $value, $is_currency = false) {
|
||||||
|
if (!empty($value)) {
|
||||||
|
$display_value = htmlspecialchars($value);
|
||||||
|
if ($is_currency) {
|
||||||
|
$display_value = '$' . number_format((float)$value, 2);
|
||||||
|
}
|
||||||
|
echo "<div class='detail-item'><span class='label'>{$label}</span><span class='value'>{$display_value}</span></div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_detail_area($label, $value) {
|
||||||
|
if (!empty($value)) {
|
||||||
|
echo "<div class='detail-area'><span class='label'>{$label}</span><pre class='value'>" . htmlspecialchars($value) . "</pre></div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
|
.detail-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem; }
|
||||||
|
.detail-actions { display: flex; gap: 1rem; }
|
||||||
|
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; }
|
||||||
|
.detail-section { background: #fff; border-radius: 12px; padding: 1.5rem; box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
|
||||||
|
.detail-section h2 { font-size: 1.3rem; margin-bottom: 1.5rem; border-bottom: 1px solid #eee; padding-bottom: 1rem; }
|
||||||
|
.detail-item { display: flex; justify-content: space-between; padding: 0.5rem 0; border-bottom: 1px solid #f5f5f5; }
|
||||||
|
.detail-item:last-child { border-bottom: none; }
|
||||||
|
.detail-item .label { font-weight: 600; color: #555; }
|
||||||
|
.detail-area { margin-top: 1rem; }
|
||||||
|
.detail-area .label { font-weight: 600; display: block; margin-bottom: 0.5rem; }
|
||||||
|
.detail-area pre { background: #f9f9f9; padding: 1rem; border-radius: 8px; white-space: pre-wrap; word-wrap: break-word; font-family: inherit; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="detail-header">
|
||||||
|
<h1><?php echo htmlspecialchars($client['full_legal_name']); ?></h1>
|
||||||
|
<div class="detail-actions">
|
||||||
|
<a href="edit_client.php?id=<?php echo $client['id']; ?>" class="btn btn-primary">Edit</a>
|
||||||
|
<form action="delete_client.php" method="POST" onsubmit="return confirm('Are you sure you want to delete this client? This cannot be undone.');">
|
||||||
|
<input type="hidden" name="id" value="<?php echo $client['id']; ?>">
|
||||||
|
<button type="submit" class="btn btn-danger">Delete</button>
|
||||||
|
</form>
|
||||||
|
<a href="clients.php" class="btn">Back to List</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-grid">
|
||||||
|
<div class="detail-section">
|
||||||
|
<h2>Client Details</h2>
|
||||||
|
<?php render_detail_item('NDIS Number', $client['ndis_client_number']); ?>
|
||||||
|
<?php render_detail_item('Date of Birth', date("d M Y", strtotime($client['date_of_birth']))); ?>
|
||||||
|
<?php render_detail_item('Contact Method', $client['preferred_contact_method']); ?>
|
||||||
|
</div>
|
||||||
|
<div class="detail-section">
|
||||||
|
<h2>Contact Info</h2>
|
||||||
|
<?php render_detail_item('Phone', $client['primary_phone']); ?>
|
||||||
|
<?php render_detail_item('Email', $client['email']); ?>
|
||||||
|
<?php render_detail_item('Address', $client['address']); ?>
|
||||||
|
<?php render_detail_item('Emergency Contact', $client['emergency_contact_name']); ?>
|
||||||
|
<?php render_detail_item('Emergency Phone', $client['emergency_contact_phone']); ?>
|
||||||
|
</div>
|
||||||
|
<div class="detail-section">
|
||||||
|
<h2>NDIS Plan</h2>
|
||||||
|
<?php render_detail_item('Plan Start', date("d M Y", strtotime($client['ndis_plan_start_date']))); ?>
|
||||||
|
<?php render_detail_item('Plan End', date("d M Y", strtotime($client['ndis_plan_end_date']))); ?>
|
||||||
|
<?php render_detail_item('Plan Manager', $client['plan_manager_name']); ?>
|
||||||
|
<?php render_detail_item('Manager Contact', $client['plan_manager_contact']); ?>
|
||||||
|
<?php render_detail_item('Total Budget', $client['ndis_funding_budget_total'], true); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-section" style="margin-top: 2rem;">
|
||||||
|
<h2>Disability, Needs & Risks</h2>
|
||||||
|
<?php render_detail_area('Primary Disability', $client['primary_disability']); ?>
|
||||||
|
<?php render_detail_area('Support Needs', $client['support_needs_summary']); ?>
|
||||||
|
<?php render_detail_area('Communication Aids', $client['communication_aids_methods']); ?>
|
||||||
|
<?php render_detail_area('Behaviours of Concern', $client['behaviours_of_concern']); ?>
|
||||||
|
<?php render_detail_area('Risk Summary', $client['risk_assessment_summary']); ?>
|
||||||
|
<?php render_detail_area('Safety Plan', $client['safety_plan']); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-section" style="margin-top: 2rem;">
|
||||||
|
<h2>Intake Notes</h2>
|
||||||
|
<?php render_detail_area('Raw notes from intake', $client['intake_notes']); ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
62
clients.php
Normal file
62
clients.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$logs = [];
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$stmt = $db->query("SELECT id, full_legal_name, ndis_client_number, primary_phone, email FROM clients ORDER BY created_at DESC");
|
||||||
|
$clients = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo '<div class="feedback error">Error: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = $_GET['message'] ?? '';
|
||||||
|
$error = $_GET['error'] ?? '';
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Clients</h1>
|
||||||
|
<a href="add_client.php" class="btn btn-primary">Add New Client</a>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php if ($message === 'deleted'): ?>
|
||||||
|
<div class="feedback success">Client successfully deleted.</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="feedback error">An error occurred. <?php echo htmlspecialchars($error); ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>NDIS Number</th>
|
||||||
|
<th>Phone</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php if (empty($clients)): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" style="text-align: center;">No clients found.</td>
|
||||||
|
</tr>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($clients as $p): ?>
|
||||||
|
<tr>
|
||||||
|
<td><?php echo htmlspecialchars($p['full_legal_name']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($p['ndis_client_number']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($p['primary_phone']); ?></td>
|
||||||
|
<td><?php echo htmlspecialchars($p['email']); ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="client_detail.php?id=<?php echo $p['id']; ?>" class="btn">View</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
152
compliance.php
Normal file
152
compliance.php
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$plan_alerts = [];
|
||||||
|
$screening_alerts = [];
|
||||||
|
$first_aid_alerts = [];
|
||||||
|
$error = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$ninety_days_from_now = date('Y-m-d', strtotime('+90 days'));
|
||||||
|
|
||||||
|
// NDIS Plan Reviews
|
||||||
|
$plan_stmt = $db->prepare("SELECT id, full_legal_name, ndis_plan_end_date FROM clients WHERE ndis_plan_end_date <= :end_date AND ndis_plan_end_date >= CURDATE() ORDER BY ndis_plan_end_date ASC");
|
||||||
|
$plan_stmt->bindParam(':end_date', $ninety_days_from_now);
|
||||||
|
$plan_stmt->execute();
|
||||||
|
$plan_alerts = $plan_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Staff Screening Expiries
|
||||||
|
$screening_stmt = $db->prepare("SELECT id, full_name, ndis_worker_screening_expiry FROM care_staff WHERE ndis_worker_screening_expiry <= :end_date AND ndis_worker_screening_expiry >= CURDATE() ORDER BY ndis_worker_screening_expiry ASC");
|
||||||
|
$screening_stmt->bindParam(':end_date', $ninety_days_from_now);
|
||||||
|
$screening_stmt->execute();
|
||||||
|
$screening_alerts = $screening_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// First Aid Expiries
|
||||||
|
$fa_stmt = $db->prepare("SELECT id, full_name, first_aid_expiry FROM care_staff WHERE first_aid_expiry <= :end_date AND first_aid_expiry >= CURDATE() ORDER BY first_aid_expiry ASC");
|
||||||
|
$fa_stmt->bindParam(':end_date', $ninety_days_from_now);
|
||||||
|
$fa_stmt->execute();
|
||||||
|
$first_aid_alerts = $fa_stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
$error = "Database Error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_days_until_badge($date) {
|
||||||
|
$now = time();
|
||||||
|
$your_date = strtotime($date);
|
||||||
|
$datediff = $your_date - $now;
|
||||||
|
$days = round($datediff / (60 * 60 * 24));
|
||||||
|
|
||||||
|
$class = ' ';
|
||||||
|
if ($days < 0) $class = 'expired';
|
||||||
|
elseif ($days <= 30) $class = 'urgent';
|
||||||
|
elseif ($days <= 60) $class = 'soon';
|
||||||
|
else $class = 'safe';
|
||||||
|
|
||||||
|
$text = ($days < 0) ? "Expired" : "{$days} days";
|
||||||
|
|
||||||
|
return "<span class=\"days-badge {$class}\">{$text}</span>";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
|
.alert-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 2rem;
|
||||||
|
}
|
||||||
|
.alert-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
.alert-card h2 {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
.alert-list li {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 1rem 0;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
.alert-list li:last-child { border-bottom: none; }
|
||||||
|
|
||||||
|
.days-badge {
|
||||||
|
padding: 0.3rem 0.8rem;
|
||||||
|
border-radius: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.days-badge.expired { background-color: #e74c3c; }
|
||||||
|
.days-badge.urgent { background-color: #f39c12; }
|
||||||
|
.days-badge.soon { background-color: #3498db; }
|
||||||
|
.days-badge.safe { background-color: #2ecc71; }
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Compliance Dashboard</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="feedback error"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="alert-grid">
|
||||||
|
<div class="alert-card">
|
||||||
|
<h2>NDIS Plan Reviews (Next 90 Days)</h2>
|
||||||
|
<ul class="alert-list">
|
||||||
|
<?php if (empty($plan_alerts)): ?>
|
||||||
|
<li>No upcoming plan reviews.</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($plan_alerts as $alert): ?>
|
||||||
|
<li>
|
||||||
|
<a href="client_detail.php?id=<?php echo $alert['id']; ?>"><?php echo htmlspecialchars($alert['full_legal_name']); ?></a>
|
||||||
|
<div><?php echo htmlspecialchars(date("d M Y", strtotime($alert['ndis_plan_end_date']))); ?> <?php echo get_days_until_badge($alert['ndis_plan_end_date']); ?></div>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert-card">
|
||||||
|
<h2>Staff Screening Expiries</h2>
|
||||||
|
<ul class="alert-list">
|
||||||
|
<?php if (empty($screening_alerts)): ?>
|
||||||
|
<li>No upcoming screening expiries.</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($screening_alerts as $alert): ?>
|
||||||
|
<li>
|
||||||
|
<a href="staff_detail.php?id=<?php echo $alert['id']; ?>"><?php echo htmlspecialchars($alert['full_name']); ?></a>
|
||||||
|
<div><?php echo htmlspecialchars(date("d M Y", strtotime($alert['ndis_worker_screening_expiry']))); ?> <?php echo get_days_until_badge($alert['ndis_worker_screening_expiry']); ?></div>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert-card">
|
||||||
|
<h2>First Aid Certificate Expiries</h2>
|
||||||
|
<ul class="alert-list">
|
||||||
|
<?php if (empty($first_aid_alerts)): ?>
|
||||||
|
<li>No upcoming First Aid expiries.</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<?php foreach ($first_aid_alerts as $alert): ?>
|
||||||
|
<li>
|
||||||
|
<a href="staff_detail.php?id=<?php echo $alert['id']; ?>"><?php echo htmlspecialchars($alert['full_name']); ?></a>
|
||||||
|
<div><?php echo htmlspecialchars(date("d M Y", strtotime($alert['first_aid_expiry']))); ?> <?php echo get_days_until_badge($alert['first_aid_expiry']); ?></div>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
38
db/setup.php
Normal file
38
db/setup.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$sql = <<<SQL
|
||||||
|
CREATE TABLE IF NOT EXISTS `clients` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`full_legal_name` VARCHAR(255) NOT NULL,
|
||||||
|
`ndis_client_number` VARCHAR(50),
|
||||||
|
`date_of_birth` DATE,
|
||||||
|
`preferred_contact_method` VARCHAR(100),
|
||||||
|
`primary_phone` VARCHAR(50),
|
||||||
|
`email` VARCHAR(255),
|
||||||
|
`address` TEXT,
|
||||||
|
`emergency_contact_name` VARCHAR(255),
|
||||||
|
`emergency_contact_phone` VARCHAR(50),
|
||||||
|
`ndis_plan_start_date` DATE,
|
||||||
|
`ndis_plan_end_date` DATE,
|
||||||
|
`plan_manager_name` VARCHAR(255),
|
||||||
|
`plan_manager_contact` VARCHAR(255),
|
||||||
|
`ndis_funding_budget_total` DECIMAL(10, 2),
|
||||||
|
`primary_disability` TEXT,
|
||||||
|
`support_needs_summary` TEXT,
|
||||||
|
`communication_aids_methods` TEXT,
|
||||||
|
`behaviours_of_concern` TEXT,
|
||||||
|
`risk_assessment_summary` TEXT,
|
||||||
|
`safety_plan` TEXT,
|
||||||
|
`consent_for_info_sharing` BOOLEAN DEFAULT FALSE,
|
||||||
|
`intake_notes` TEXT
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
$db->exec($sql);
|
||||||
|
echo "Table `clients` created successfully." . PHP_EOL;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
25
db/setup_bookings.php
Normal file
25
db/setup_bookings.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$sql = <<<SQL
|
||||||
|
CREATE TABLE IF NOT EXISTS `bookings` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`client_id` INT NOT NULL,
|
||||||
|
`staff_id` INT NOT NULL,
|
||||||
|
`service_date` DATETIME NOT NULL,
|
||||||
|
`ndis_line_item` VARCHAR(255),
|
||||||
|
`duration_minutes` INT,
|
||||||
|
`service_notes` TEXT,
|
||||||
|
`billing_status` ENUM('Pending', 'Billed', 'Paid') DEFAULT 'Pending',
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (`client_id`) REFERENCES `clients`(`id`) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (`staff_id`) REFERENCES `care_staff`(`id`) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
$db->exec($sql);
|
||||||
|
echo "Table `bookings` created successfully." . PHP_EOL;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
23
db/setup_care_staff.php
Normal file
23
db/setup_care_staff.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$sql = <<<SQL
|
||||||
|
CREATE TABLE IF NOT EXISTS `care_staff` (
|
||||||
|
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`full_name` VARCHAR(255) NOT NULL,
|
||||||
|
`contact_info` TEXT,
|
||||||
|
`ndis_worker_screening_number` VARCHAR(100),
|
||||||
|
`ndis_worker_screening_expiry` DATE,
|
||||||
|
`first_aid_expiry` DATE,
|
||||||
|
`qualifications` TEXT,
|
||||||
|
`hourly_rate` DECIMAL(10, 2)
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
$db->exec($sql);
|
||||||
|
echo "Table `care_staff` created successfully." . PHP_EOL;
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
die("DB ERROR: " . $e->getMessage());
|
||||||
|
}
|
||||||
33
delete_client.php
Normal file
33
delete_client.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
||||||
|
header('Location: clients.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($_POST['id']) || !filter_var($_POST['id'], FILTER_VALIDATE_INT)) {
|
||||||
|
header('Location: clients.php?error=invalid_id');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$client_id = $_POST['id'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$stmt = $db->prepare("DELETE FROM clients WHERE id = :id");
|
||||||
|
$stmt->bindParam(':id', $client_id, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
if ($stmt->rowCount() > 0) {
|
||||||
|
header('Location: clients.php?message=deleted');
|
||||||
|
} else {
|
||||||
|
header('Location: clients.php?error=not_found');
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
// In a real app, you'd log this error, not expose it
|
||||||
|
header('Location: clients.php?error=db_error');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
256
edit_client.php
Normal file
256
edit_client.php
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$error = '';
|
||||||
|
$client = null;
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) && !isset($_POST['id'])) {
|
||||||
|
echo '<div class="feedback error">No client ID specified.</div>';
|
||||||
|
require_once 'footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$client_id = $_GET['id'] ?? $_POST['id'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$stmt = $db->prepare("SELECT * FROM clients WHERE id = :id");
|
||||||
|
$stmt->bindParam(':id', $client_id, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$client = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$client) {
|
||||||
|
throw new Exception("Client not found.");
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = "Error: " . $e->getMessage();
|
||||||
|
echo "<div class='feedback error'>$error</div>";
|
||||||
|
require_once 'footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
|
||||||
|
$required_fields = ['full_legal_name', 'id'];
|
||||||
|
foreach ($required_fields as $field) {
|
||||||
|
if (empty($_POST[$field])) {
|
||||||
|
throw new Exception("'$field' is a required field.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "UPDATE clients SET
|
||||||
|
full_legal_name = :full_legal_name,
|
||||||
|
ndis_client_number = :ndis_client_number,
|
||||||
|
date_of_birth = :date_of_birth,
|
||||||
|
preferred_contact_method = :preferred_contact_method,
|
||||||
|
primary_phone = :primary_phone,
|
||||||
|
email = :email,
|
||||||
|
address = :address,
|
||||||
|
emergency_contact_name = :emergency_contact_name,
|
||||||
|
emergency_contact_phone = :emergency_contact_phone,
|
||||||
|
ndis_plan_start_date = :ndis_plan_start_date,
|
||||||
|
ndis_plan_end_date = :ndis_plan_end_date,
|
||||||
|
plan_manager_name = :plan_manager_name,
|
||||||
|
plan_manager_contact = :plan_manager_contact,
|
||||||
|
ndis_funding_budget_total = :ndis_funding_budget_total,
|
||||||
|
primary_disability = :primary_disability,
|
||||||
|
support_needs_summary = :support_needs_summary,
|
||||||
|
communication_aids_methods = :communication_aids_methods,
|
||||||
|
behaviours_of_concern = :behaviours_of_concern,
|
||||||
|
risk_assessment_summary = :risk_assessment_summary,
|
||||||
|
safety_plan = :safety_plan,
|
||||||
|
consent_for_info_sharing = :consent_for_info_sharing,
|
||||||
|
intake_notes = :intake_notes
|
||||||
|
WHERE id = :id";
|
||||||
|
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
|
||||||
|
$consent = isset($_POST['consent_for_info_sharing']) ? 1 : 0;
|
||||||
|
$client_id = $_POST['id'];
|
||||||
|
|
||||||
|
$stmt->bindParam(':id', $client_id, PDO::PARAM_INT);
|
||||||
|
$stmt->bindParam(':full_legal_name', $_POST['full_legal_name']);
|
||||||
|
$stmt->bindParam(':ndis_client_number', $_POST['ndis_client_number']);
|
||||||
|
$stmt->bindParam(':date_of_birth', $_POST['date_of_birth']);
|
||||||
|
$stmt->bindParam(':preferred_contact_method', $_POST['preferred_contact_method']);
|
||||||
|
$stmt->bindParam(':primary_phone', $_POST['primary_phone']);
|
||||||
|
$stmt->bindParam(':email', $_POST['email']);
|
||||||
|
$stmt->bindParam(':address', $_POST['address']);
|
||||||
|
$stmt->bindParam(':emergency_contact_name', $_POST['emergency_contact_name']);
|
||||||
|
$stmt->bindParam(':emergency_contact_phone', $_POST['emergency_contact_phone']);
|
||||||
|
$stmt->bindParam(':ndis_plan_start_date', $_POST['ndis_plan_start_date']);
|
||||||
|
$stmt->bindParam(':ndis_plan_end_date', $_POST['ndis_plan_end_date']);
|
||||||
|
$stmt->bindParam(':plan_manager_name', $_POST['plan_manager_name']);
|
||||||
|
$stmt->bindParam(':plan_manager_contact', $_POST['plan_manager_contact']);
|
||||||
|
$stmt->bindParam(':ndis_funding_budget_total', $_POST['ndis_funding_budget_total']);
|
||||||
|
$stmt->bindParam(':primary_disability', $_POST['primary_disability']);
|
||||||
|
$stmt->bindParam(':support_needs_summary', $_POST['support_needs_summary']);
|
||||||
|
$stmt->bindParam(':communication_aids_methods', $_POST['communication_aids_methods']);
|
||||||
|
$stmt->bindParam(':behaviours_of_concern', $_POST['behaviours_of_concern']);
|
||||||
|
$stmt->bindParam(':risk_assessment_summary', $_POST['risk_assessment_summary']);
|
||||||
|
$stmt->bindParam(':safety_plan', $_POST['safety_plan']);
|
||||||
|
$stmt->bindParam(':consent_for_info_sharing', $consent, PDO::PARAM_INT);
|
||||||
|
$stmt->bindParam(':intake_notes', $_POST['intake_notes']);
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
header("Location: client_detail.php?id=" . $client_id . "&message=updated");
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = "Error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
|
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; }
|
||||||
|
.form-section { background-color: #fdfdfd; padding: 1.5rem; border-radius: 8px; border: 1px solid #eee; }
|
||||||
|
.form-section h3 { font-size: 1.2rem; margin-bottom: 1.5rem; border-bottom: 1px solid #eee; padding-bottom: 1rem; }
|
||||||
|
.ai-section { background-color: #eaf5ff; padding: 1.5rem; border-radius: 8px; margin-bottom: 2rem; border: 1px solid #c7dfff; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Edit Client: <?php echo htmlspecialchars($client['full_legal_name']); ?></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="feedback success"><?php echo $message; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="feedback error"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="edit_client.php" method="POST">
|
||||||
|
<input type="hidden" name="id" value="<?php echo $client['id']; ?>">
|
||||||
|
|
||||||
|
<div class="ai-section">
|
||||||
|
<h3>AI-Assisted Intake</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="intake_notes">Raw Intake Notes</label>
|
||||||
|
<textarea id="intake_notes" name="intake_notes" rows="6" placeholder="Paste the full, unstructured intake notes here..."><?php echo htmlspecialchars($client['intake_notes']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="btn btn-secondary" id="summarize-with-ai">Summarize with AI</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-grid">
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Client Details</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="full_legal_name">Full Legal Name *</label>
|
||||||
|
<input type="text" id="full_legal_name" name="full_legal_name" value="<?php echo htmlspecialchars($client['full_legal_name']); ?>" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_client_number">NDIS Client Number</label>
|
||||||
|
<input type="text" id="ndis_client_number" name="ndis_client_number" value="<?php echo htmlspecialchars($client['ndis_client_number']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="date_of_birth">Date of Birth</label>
|
||||||
|
<input type="date" id="date_of_birth" name="date_of_birth" value="<?php echo htmlspecialchars($client['date_of_birth']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="preferred_contact_method">Preferred Contact Method</label>
|
||||||
|
<input type="text" id="preferred_contact_method" name="preferred_contact_method" value="<?php echo htmlspecialchars($client['preferred_contact_method']); ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Contact Info</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="primary_phone">Primary Phone</label>
|
||||||
|
<input type="tel" id="primary_phone" name="primary_phone" value="<?php echo htmlspecialchars($client['primary_phone']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email">Email</label>
|
||||||
|
<input type="email" id="email" name="email" value="<?php echo htmlspecialchars($client['email']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="address">Address</label>
|
||||||
|
<textarea id="address" name="address" rows="1"><?php echo htmlspecialchars($client['address']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="emergency_contact_name">Emergency Contact Name</label>
|
||||||
|
<input type="text" id="emergency_contact_name" name="emergency_contact_name" value="<?php echo htmlspecialchars($client['emergency_contact_name']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="emergency_contact_phone">Emergency Contact Phone</label>
|
||||||
|
<input type="tel" id="emergency_contact_phone" name="emergency_contact_phone" value="<?php echo htmlspecialchars($client['emergency_contact_phone']); ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Plan Details</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_plan_start_date">NDIS Plan Start Date</label>
|
||||||
|
<input type="date" id="ndis_plan_start_date" name="ndis_plan_start_date" value="<?php echo htmlspecialchars($client['ndis_plan_start_date']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_plan_end_date">NDIS Plan End Date</label>
|
||||||
|
<input type="date" id="ndis_plan_end_date" name="ndis_plan_end_date" value="<?php echo htmlspecialchars($client['ndis_plan_end_date']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="plan_manager_name">Plan Manager Name</label>
|
||||||
|
<input type="text" id="plan_manager_name" name="plan_manager_name" value="<?php echo htmlspecialchars($client['plan_manager_name']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="plan_manager_contact">Plan Manager Contact</label>
|
||||||
|
<input type="text" id="plan_manager_contact" name="plan_manager_contact" value="<?php echo htmlspecialchars($client['plan_manager_contact']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_funding_budget_total">NDIS Funding Budget (Total)</label>
|
||||||
|
<input type="number" step="0.01" id="ndis_funding_budget_total" name="ndis_funding_budget_total" value="<?php echo htmlspecialchars($client['ndis_funding_budget_total']); ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Disability & Needs</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="primary_disability">Primary Disability</label>
|
||||||
|
<textarea id="primary_disability" name="primary_disability" rows="2"><?php echo htmlspecialchars($client['primary_disability']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="support_needs_summary">Support Needs Summary</label>
|
||||||
|
<textarea id="support_needs_summary" name="support_needs_summary" rows="2"><?php echo htmlspecialchars($client['support_needs_summary']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="communication_aids_methods">Communication Aids/Methods</label>
|
||||||
|
<textarea id="communication_aids_methods" name="communication_aids_methods" rows="2"><?php echo htmlspecialchars($client['communication_aids_methods']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Risk & Safety</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="behaviours_of_concern">Known Behaviours of Concern</label>
|
||||||
|
<textarea id="behaviours_of_concern" name="behaviours_of_concern" rows="3"><?php echo htmlspecialchars($client['behaviours_of_concern']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="risk_assessment_summary">Detailed Risk Assessment Summary</label>
|
||||||
|
<textarea id="risk_assessment_summary" name="risk_assessment_summary" rows="3"><?php echo htmlspecialchars($client['risk_assessment_summary']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="safety_plan">Safety/Restrictive Practices Plan</label>
|
||||||
|
<textarea id="safety_plan" name="safety_plan" rows="3"><?php echo htmlspecialchars($client['safety_plan']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-section">
|
||||||
|
<h3>Consent</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="checkbox" id="consent_for_info_sharing" name="consent_for_info_sharing" value="1" <?php echo $client['consent_for_info_sharing'] ? 'checked' : ''; ?> style="width: auto; margin-right: 10px;">
|
||||||
|
<label for="consent_for_info_sharing">Consent for information sharing has been recorded.</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 2rem;">
|
||||||
|
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||||
|
<a href="client_detail.php?id=<?php echo $client['id']; ?>" class="btn">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
127
edit_staff.php
Normal file
127
edit_staff.php
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$error = '';
|
||||||
|
$staff = null;
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) && !isset($_POST['id'])) {
|
||||||
|
echo '<div class="feedback error">No staff ID specified.</div>';
|
||||||
|
require_once 'footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$staff_id = $_GET['id'] ?? $_POST['id'];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$stmt = $db->prepare("SELECT * FROM care_staff WHERE id = :id");
|
||||||
|
$stmt->bindParam(':id', $staff_id, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$staff = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$staff) {
|
||||||
|
throw new Exception("Care staff member not found.");
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = "Error: " . $e->getMessage();
|
||||||
|
echo "<div class='feedback error'>$error</div>";
|
||||||
|
require_once 'footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
|
||||||
|
if (empty($_POST['full_name']) || empty($_POST['id'])) {
|
||||||
|
throw new Exception("Full Name and ID are required fields.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "UPDATE care_staff SET
|
||||||
|
full_name = :full_name,
|
||||||
|
contact_info = :contact_info,
|
||||||
|
ndis_worker_screening_number = :ndis_worker_screening_number,
|
||||||
|
ndis_worker_screening_expiry = :ndis_worker_screening_expiry,
|
||||||
|
first_aid_expiry = :first_aid_expiry,
|
||||||
|
qualifications = :qualifications,
|
||||||
|
hourly_rate = :hourly_rate
|
||||||
|
WHERE id = :id";
|
||||||
|
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
|
||||||
|
$staff_id = $_POST['id'];
|
||||||
|
|
||||||
|
$stmt->bindParam(':id', $staff_id, PDO::PARAM_INT);
|
||||||
|
$stmt->bindParam(':full_name', $_POST['full_name']);
|
||||||
|
$stmt->bindParam(':contact_info', $_POST['contact_info']);
|
||||||
|
$stmt->bindParam(':ndis_worker_screening_number', $_POST['ndis_worker_screening_number']);
|
||||||
|
$stmt->bindParam(':ndis_worker_screening_expiry', $_POST['ndis_worker_screening_expiry']);
|
||||||
|
$stmt->bindParam(':first_aid_expiry', $_POST['first_aid_expiry']);
|
||||||
|
$stmt->bindParam(':qualifications', $_POST['qualifications']);
|
||||||
|
$stmt->bindParam(':hourly_rate', $_POST['hourly_rate']);
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
header("Location: staff_detail.php?id=" . $staff_id . "&message=updated");
|
||||||
|
exit;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = "Error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Edit Staff Member: <?php echo htmlspecialchars($staff['full_name']); ?></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="feedback success"><?php echo $message; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="feedback error"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="edit_staff.php" method="POST">
|
||||||
|
<input type="hidden" name="id" value="<?php echo $staff['id']; ">
|
||||||
|
<div class="form-grid" style="grid-template-columns: 1fr;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="full_name">Full Name *</label>
|
||||||
|
<input type="text" id="full_name" name="full_name" value="<?php echo htmlspecialchars($staff['full_name']); ?>" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="contact_info">Contact Info (Phone/Email)</label>
|
||||||
|
<textarea id="contact_info" name="contact_info" rows="2"><?php echo htmlspecialchars($staff['contact_info']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="qualifications">Qualifications/Certificates</label>
|
||||||
|
<textarea id="qualifications" name="qualifications" rows="3"><?php echo htmlspecialchars($staff['qualifications']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_worker_screening_number">NDIS Staff Screening Check Number</label>
|
||||||
|
<input type="text" id="ndis_worker_screening_number" name="ndis_worker_screening_number" value="<?php echo htmlspecialchars($staff['ndis_worker_screening_number']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_worker_screening_expiry">Screening Check Expiry Date</label>
|
||||||
|
<input type="date" id="ndis_worker_screening_expiry" name="ndis_worker_screening_expiry" value="<?php echo htmlspecialchars($staff['ndis_worker_screening_expiry']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="first_aid_expiry">First Aid Certificate Expiry Date</label>
|
||||||
|
<input type="date" id="first_aid_expiry" name="first_aid_expiry" value="<?php echo htmlspecialchars($staff['first_aid_expiry']); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="hourly_rate">Hourly Rate</label>
|
||||||
|
<input type="number" step="0.01" id="hourly_rate" name="hourly_rate" value="<?php echo htmlspecialchars($staff['hourly_rate']); ?>">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 2rem;">
|
||||||
|
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||||
|
<a href="staff_detail.php?id=<?php echo $staff['id']; ?>" class="btn">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
3
footer.php
Normal file
3
footer.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
37
header.php
Normal file
37
header.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>NDIS Mini CRM</title>
|
||||||
|
<link rel="stylesheet" href="assets/css/style.css?v=<?php echo time(); ?>">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script src="assets/js/main.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$current_page = basename($_SERVER['PHP_SELF']);
|
||||||
|
$pages = [
|
||||||
|
'index.php' => 'Dashboard',
|
||||||
|
'clients.php' => 'Clients',
|
||||||
|
'care_staff.php' => 'Care Staff',
|
||||||
|
'bookings.php' => 'Bookings', 'compliance.php' => 'Compliance',
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="sidebar">
|
||||||
|
<h1 class="logo">NDIS CRM</h1>
|
||||||
|
<nav>
|
||||||
|
<?php foreach ($pages as $url => $title): ?>
|
||||||
|
<a href="<?php echo $url; ?>" class="<?php echo ($current_page == $url) ? 'active' : ''; ?>">
|
||||||
|
<?php echo $title; ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</nav>
|
||||||
|
<div class="footer">
|
||||||
|
<p>© <?php echo date("Y"); ?> NDIS CRM</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="main-content">
|
||||||
280
index.php
280
index.php
@ -1,150 +1,140 @@
|
|||||||
<?php
|
<?php
|
||||||
declare(strict_types=1);
|
require_once 'db/config.php';
|
||||||
@ini_set('display_errors', '1');
|
require_once 'header.php';
|
||||||
@error_reporting(E_ALL);
|
|
||||||
@date_default_timezone_set('UTC');
|
// Fetch counts for dashboard cards
|
||||||
|
$client_count = db()->query("SELECT COUNT(*) FROM clients")->fetchColumn();
|
||||||
|
$staff_count = db()->query("SELECT COUNT(*) FROM care_staff")->fetchColumn();
|
||||||
|
$booking_count = db()->query("SELECT COUNT(*) FROM bookings")->fetchColumn();
|
||||||
|
|
||||||
|
// Fetch upcoming compliance alerts (e.g., expiring in 90 days)
|
||||||
|
$ninety_days_from_now = date('Y-m-d', strtotime('+90 days'));
|
||||||
|
$compliance_alerts = db()->query("SELECT COUNT(*) FROM clients WHERE ndis_plan_end_date <= '$ninety_days_from_now'")->fetchColumn();
|
||||||
|
$worker_alerts = db()->query("SELECT COUNT(*) FROM care_staff WHERE ndis_worker_screening_expiry <= '$ninety_days_from_now' OR first_aid_expiry <= '$ninety_days_from_now'")->fetchColumn();
|
||||||
|
$total_alerts = $compliance_alerts + $worker_alerts;
|
||||||
|
|
||||||
|
// Chart Data
|
||||||
|
// Clients per month
|
||||||
|
$clients_per_month_q = db()->query("SELECT DATE_FORMAT(created_at, '%Y-%m') as month, COUNT(*) as count FROM clients GROUP BY month ORDER BY month");
|
||||||
|
$clients_per_month = $clients_per_month_q->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
$client_months = json_encode(array_column($clients_per_month, 'month'));
|
||||||
|
$client_counts = json_encode(array_column($clients_per_month, 'count'));
|
||||||
|
|
||||||
|
// Bookings per month
|
||||||
|
$bookings_per_month_q = db()->query("SELECT DATE_FORMAT(service_date, '%Y-%m') as month, COUNT(*) as count FROM bookings GROUP BY month ORDER BY month");
|
||||||
|
$bookings_per_month = $bookings_per_month_q->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
$booking_months = json_encode(array_column($bookings_per_month, 'month'));
|
||||||
|
$booking_counts = json_encode(array_column($bookings_per_month, 'count'));
|
||||||
|
|
||||||
|
// Billing status
|
||||||
|
$billing_status_q = db()->query("SELECT billing_status, COUNT(*) as count FROM bookings GROUP BY billing_status");
|
||||||
|
$billing_status = $billing_status_q->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
$billing_status_labels = json_encode(array_column($billing_status, 'billing_status'));
|
||||||
|
$billing_status_counts = json_encode(array_column($billing_status, 'count'));
|
||||||
|
|
||||||
$phpVersion = PHP_VERSION;
|
|
||||||
$now = date('Y-m-d H:i:s');
|
|
||||||
?>
|
?>
|
||||||
<!doctype html>
|
|
||||||
<html lang="en">
|
<header>
|
||||||
<head>
|
<h1>Dashboard</h1>
|
||||||
<meta charset="utf-8" />
|
<a href="log_booking.php" class="btn btn-primary">Log a New Booking</a>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
</header>
|
||||||
<title>New Style</title>
|
|
||||||
<?php
|
<div class="card-container">
|
||||||
// Read project preview data from environment
|
|
||||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
|
||||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
|
||||||
?>
|
|
||||||
<?php if ($projectDescription): ?>
|
|
||||||
<!-- Meta description -->
|
|
||||||
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
|
|
||||||
<!-- Open Graph meta tags -->
|
|
||||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
|
||||||
<!-- Twitter meta tags -->
|
|
||||||
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($projectImageUrl): ?>
|
|
||||||
<!-- Open Graph image -->
|
|
||||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
|
||||||
<!-- Twitter image -->
|
|
||||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
|
||||||
<?php endif; ?>
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
|
||||||
<style>
|
|
||||||
:root {
|
|
||||||
--bg-color-start: #6a11cb;
|
|
||||||
--bg-color-end: #2575fc;
|
|
||||||
--text-color: #ffffff;
|
|
||||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
|
||||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: 'Inter', sans-serif;
|
|
||||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
|
||||||
color: var(--text-color);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 100vh;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
body::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
|
||||||
animation: bg-pan 20s linear infinite;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
@keyframes bg-pan {
|
|
||||||
0% { background-position: 0% 0%; }
|
|
||||||
100% { background-position: 100% 100%; }
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
.card {
|
|
||||||
background: var(--card-bg-color);
|
|
||||||
border: 1px solid var(--card-border-color);
|
|
||||||
border-radius: 16px;
|
|
||||||
padding: 2rem;
|
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
-webkit-backdrop-filter: blur(20px);
|
|
||||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
.loader {
|
|
||||||
margin: 1.25rem auto 1.25rem;
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
|
||||||
border-top-color: #fff;
|
|
||||||
border-radius: 50%;
|
|
||||||
animation: spin 1s linear infinite;
|
|
||||||
}
|
|
||||||
@keyframes spin {
|
|
||||||
from { transform: rotate(0deg); }
|
|
||||||
to { transform: rotate(360deg); }
|
|
||||||
}
|
|
||||||
.hint {
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
.sr-only {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px; height: 1px;
|
|
||||||
padding: 0; margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0, 0, 0, 0);
|
|
||||||
white-space: nowrap; border: 0;
|
|
||||||
}
|
|
||||||
h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
font-weight: 700;
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
letter-spacing: -1px;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
margin: 0.5rem 0;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
code {
|
|
||||||
background: rgba(0,0,0,0.2);
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
||||||
}
|
|
||||||
footer {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 1rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<main>
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h1>Analyzing your requirements and generating your website…</h1>
|
<h3>Total Clients</h3>
|
||||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
<p><?php echo $client_count; ?></p>
|
||||||
<span class="sr-only">Loading…</span>
|
<a href="clients.php" class="card-link">Manage Clients →</a>
|
||||||
</div>
|
|
||||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
|
||||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
|
||||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
|
||||||
</div>
|
</div>
|
||||||
</main>
|
<div class="card">
|
||||||
<footer>
|
<h3>Total Care Staff</h3>
|
||||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
<p><?php echo $staff_count; ?></p>
|
||||||
</footer>
|
<a href="care_staff.php" class="card-link">Manage Care Staff →</a>
|
||||||
</body>
|
</div>
|
||||||
</html>
|
<div class="card">
|
||||||
|
<h3>Bookings Logged</h3>
|
||||||
|
<p><?php echo $booking_count; ?></p>
|
||||||
|
<a href="bookings.php" class="card-link">View Bookings →</a>
|
||||||
|
</div>
|
||||||
|
<div class="card">
|
||||||
|
<h3>Compliance Alerts</h3>
|
||||||
|
<p><?php echo $total_alerts; ?></p>
|
||||||
|
<a href="compliance.php" class="card-link">View Alerts →</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="charts-container">
|
||||||
|
<div class="chart-card">
|
||||||
|
<h3>Clients Added Per Month</h3>
|
||||||
|
<canvas id="clientsChart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="chart-card">
|
||||||
|
<h3>Bookings Per Month</h3>
|
||||||
|
<canvas id="bookingsChart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="chart-card">
|
||||||
|
<h3>Booking Billing Status</h3>
|
||||||
|
<canvas id="billingChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
// Clients Chart
|
||||||
|
var clientsCtx = document.getElementById('clientsChart').getContext('2d');
|
||||||
|
new Chart(clientsCtx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: <?php echo $client_months; ?>,
|
||||||
|
datasets: [{
|
||||||
|
label: 'New Clients',
|
||||||
|
data: <?php echo $client_counts; ?>,
|
||||||
|
backgroundColor: 'rgba(54, 162, 235, 0.2)',
|
||||||
|
borderColor: 'rgba(54, 162, 235, 1)',
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bookings Chart
|
||||||
|
var bookingsCtx = document.getElementById('bookingsChart').getContext('2d');
|
||||||
|
new Chart(bookingsCtx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: <?php echo $booking_months; ?>,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Bookings Logged',
|
||||||
|
data: <?php echo $booking_counts; ?>,
|
||||||
|
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
||||||
|
borderColor: 'rgba(255, 99, 132, 1)',
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Billing Status Chart
|
||||||
|
var billingCtx = document.getElementById('billingChart').getContext('2d');
|
||||||
|
new Chart(billingCtx, {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
labels: <?php echo $billing_status_labels; ?>,
|
||||||
|
datasets: [{
|
||||||
|
label: 'Billing Status',
|
||||||
|
data: <?php echo $billing_status_counts; ?>,
|
||||||
|
backgroundColor: [
|
||||||
|
'rgba(255, 206, 86, 0.2)',
|
||||||
|
'rgba(75, 192, 192, 0.2)',
|
||||||
|
'rgba(153, 102, 255, 0.2)'
|
||||||
|
],
|
||||||
|
borderColor: [
|
||||||
|
'rgba(255, 206, 86, 1)',
|
||||||
|
'rgba(75, 192, 192, 1)',
|
||||||
|
'rgba(153, 102, 255, 1)'
|
||||||
|
],
|
||||||
|
borderWidth: 1
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
117
log_booking.php
Normal file
117
log_booking.php
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
$message = '';
|
||||||
|
$error = '';
|
||||||
|
$clients = [];
|
||||||
|
$care_staff = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$clients = $db->query("SELECT id, full_legal_name FROM clients ORDER BY full_legal_name ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
$care_staff = $db->query("SELECT id, full_name FROM care_staff ORDER BY full_name ASC")->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = "Failed to fetch clients or care staff: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
|
try {
|
||||||
|
if (empty($_POST['client_id']) || empty($_POST['staff_id']) || empty($_POST['service_date'])) {
|
||||||
|
throw new Exception("Client, Care Staff, and Service Date are required fields.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = db();
|
||||||
|
$sql = "INSERT INTO bookings (
|
||||||
|
client_id, staff_id, service_date, ndis_line_item,
|
||||||
|
duration_minutes, service_notes, billing_status
|
||||||
|
) VALUES (
|
||||||
|
:client_id, :staff_id, :service_date, :ndis_line_item,
|
||||||
|
:duration_minutes, :service_notes, :billing_status
|
||||||
|
)";
|
||||||
|
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
|
||||||
|
$stmt->bindParam(':client_id', $_POST['client_id'], PDO::PARAM_INT);
|
||||||
|
$stmt->bindParam(':staff_id', $_POST['staff_id'], PDO::PARAM_INT);
|
||||||
|
$stmt->bindParam(':service_date', $_POST['service_date']);
|
||||||
|
$stmt->bindParam(':ndis_line_item', $_POST['ndis_line_item']);
|
||||||
|
$stmt->bindParam(':duration_minutes', $_POST['duration_minutes'], PDO::PARAM_INT);
|
||||||
|
$stmt->bindParam(':service_notes', $_POST['service_notes']);
|
||||||
|
$stmt->bindParam(':billing_status', $_POST['billing_status']);
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$message = "Booking successfully added!";
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$error = "Error: " . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Log a New Booking</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php if ($message): ?>
|
||||||
|
<div class="feedback success"><?php echo $message; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($error): ?>
|
||||||
|
<div class="feedback error"><?php echo $error; ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form action="log_booking.php" method="POST">
|
||||||
|
<div class="form-grid">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="client_id">Client *</label>
|
||||||
|
<select id="client_id" name="client_id" required>
|
||||||
|
<option value="">Select a client...</option>
|
||||||
|
<?php foreach ($clients as $p): ?>
|
||||||
|
<option value="<?php echo $p['id']; ?>"><?php echo htmlspecialchars($p['full_legal_name']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="staff_id">Care Staff *</label>
|
||||||
|
<select id="staff_id" name="staff_id" required>
|
||||||
|
<option value="">Select a staff member...</option>
|
||||||
|
<?php foreach ($care_staff as $w): ?>
|
||||||
|
<option value="<?php echo $w['id']; ?>"><?php echo htmlspecialchars($w['full_name']); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="service_date">Service Date & Time *</label>
|
||||||
|
<input type="datetime-local" id="service_date" name="service_date" required>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="duration_minutes">Duration (minutes)</label>
|
||||||
|
<input type="number" id="duration_minutes" name="duration_minutes">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="ndis_line_item">NDIS Line Item Code</label>
|
||||||
|
<input type="text" id="ndis_line_item" name="ndis_line_item" placeholder="e.g., 01_001_0107_5_1">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="billing_status">Billing Status</label>
|
||||||
|
<select id="billing_status" name="billing_status">
|
||||||
|
<option value="Pending">Pending</option>
|
||||||
|
<option value="Billed">Billed</option>
|
||||||
|
<option value="Paid">Paid</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="margin-top: 1.5rem;">
|
||||||
|
<label for="service_notes">Brief Service Note/Outcome</label>
|
||||||
|
<textarea id="service_notes" name="service_notes" rows="4"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-top: 2rem;">
|
||||||
|
<button type="submit" class="btn btn-primary">Log Booking</button>
|
||||||
|
<a href="bookings.php" class="btn">Cancel</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
91
staff_detail.php
Normal file
91
staff_detail.php
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'db/config.php';
|
||||||
|
require_once 'header.php';
|
||||||
|
|
||||||
|
if (!isset($_GET['id']) || !filter_var($_GET['id'], FILTER_VALIDATE_INT)) {
|
||||||
|
echo '<div class="feedback error">Invalid staff ID.</div>';
|
||||||
|
require_once 'footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$staff_id = $_GET['id'];
|
||||||
|
$staff = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = db();
|
||||||
|
$stmt = $db->prepare("SELECT * FROM care_staff WHERE id = :id");
|
||||||
|
$stmt->bindParam(':id', $staff_id, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$staff = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
echo '<div class="feedback error">Error: ' . $e->getMessage() . '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$staff) {
|
||||||
|
echo '<div class="feedback error">Care staff member not found.</div>';
|
||||||
|
require_once 'footer.php';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_detail_item($label, $value, $is_currency = false) {
|
||||||
|
if (!empty($value)) {
|
||||||
|
$display_value = htmlspecialchars($value);
|
||||||
|
if ($is_currency) {
|
||||||
|
$display_value = '$' . number_format((float)$value, 2);
|
||||||
|
}
|
||||||
|
echo "<div class='detail-item'><span class='label'>{$label}</span><span class='value'>{$display_value}</span></div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_detail_area($label, $value) {
|
||||||
|
if (!empty($value)) {
|
||||||
|
echo "<div class='detail-area'><span class='label'>{$label}</span><pre class='value'>" . htmlspecialchars($value) . "</pre></div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<style>
|
||||||
|
.detail-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem; }
|
||||||
|
.detail-actions { display: flex; gap: 1rem; }
|
||||||
|
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 2rem; }
|
||||||
|
.detail-section { background: #fff; border-radius: 12px; padding: 1.5rem; box-shadow: 0 4px 12px rgba(0,0,0,0.05); }
|
||||||
|
.detail-section h2 { font-size: 1.3rem; margin-bottom: 1.5rem; border-bottom: 1px solid #eee; padding-bottom: 1rem; }
|
||||||
|
.detail-item { display: flex; justify-content: space-between; padding: 0.5rem 0; border-bottom: 1px solid #f5f5f5; }
|
||||||
|
.detail-item:last-child { border-bottom: none; }
|
||||||
|
.detail-item .label { font-weight: 600; color: #555; }
|
||||||
|
.detail-area { margin-top: 1rem; }
|
||||||
|
.detail-area .label { font-weight: 600; display: block; margin-bottom: 0.5rem; }
|
||||||
|
.detail-area pre { background: #f9f9f9; padding: 1rem; border-radius: 8px; white-space: pre-wrap; word-wrap: break-word; font-family: inherit; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="detail-header">
|
||||||
|
<h1><?php echo htmlspecialchars($staff['full_name']); ?></h1>
|
||||||
|
<div class="detail-actions">
|
||||||
|
<a href="edit_staff.php?id=<?php echo $staff['id']; ?>" class="btn btn-primary">Edit</a>
|
||||||
|
<form action="delete_staff.php" method="POST" onsubmit="return confirm('Are you sure you want to delete this staff member? This cannot be undone.');">
|
||||||
|
<input type="hidden" name="id" value="<?php echo $staff['id']; ?>">
|
||||||
|
<button type="submit" class="btn btn-danger">Delete</button>
|
||||||
|
</form>
|
||||||
|
<a href="care_staff.php" class="btn">Back to List</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="detail-grid">
|
||||||
|
<div class="detail-section">
|
||||||
|
<h2>Personal & Contact</h2>
|
||||||
|
<?php render_detail_item('Full Name', $staff['full_name']); ?>
|
||||||
|
<?php render_detail_area('Contact Info', $staff['contact_info']); ?>
|
||||||
|
</div>
|
||||||
|
<div class="detail-section">
|
||||||
|
<h2>Compliance</h2>
|
||||||
|
<?php render_detail_item('Screening Number', $staff['ndis_worker_screening_number']); ?>
|
||||||
|
<?php render_detail_item('Screening Expiry', date("d M Y", strtotime($staff['ndis_worker_screening_expiry']))); ?>
|
||||||
|
<?php render_detail_item('First Aid Expiry', date("d M Y", strtotime($staff['first_aid_expiry']))); ?>
|
||||||
|
</div>
|
||||||
|
<div class="detail-section">
|
||||||
|
<h2>Work Details</h2>
|
||||||
|
<?php render_detail_item('Hourly Rate', $staff['hourly_rate'], true); ?>
|
||||||
|
<?php render_detail_area('Qualifications', $staff['qualifications']); ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php require_once 'footer.php'; ?>
|
||||||
Loading…
x
Reference in New Issue
Block a user