Ver Fonte

Crop Card Index

Benjamin Harris há 2 meses atrás
pai
commit
908f5bcac4
4 ficheiros alterados com 882 adições e 847 exclusões
  1. 92 0
      controllers/blockSubmit.php
  2. 482 790
      dashboard/crop-cards/index.php
  3. 185 14
      dashboard/dashboard.php
  4. 123 43
      login/change-password.php

+ 92 - 0
controllers/blockSubmit.php

@@ -0,0 +1,92 @@
+<?php
+/**
+ * controllers/blockSubmit.php
+ *
+ * Handles Create and Edit (update) submissions for block_info records.
+ * Redirects back to /dashboard/crop-cards/ on success or failure.
+ */
+
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
+}
+
+require_once __DIR__ . '/../config/database.php';
+require_once __DIR__ . '/../lib/auth.php';
+require_once __DIR__ . '/../lib/csrf.php';
+
+requireLogin();
+
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+    header('Location: /dashboard/crop-cards/');
+    exit;
+}
+
+if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) {
+    $_SESSION['flash_error'] = 'Invalid security token. Please try again.';
+    header('Location: /dashboard/crop-cards/');
+    exit;
+}
+
+$action    = $_POST['action'] ?? '';
+$userId    = getCurrentUserId();
+$pdo       = getDBConnection();
+
+// Shared field sanitisation
+$name      = trim($_POST['name']      ?? '');
+$blockId   = trim($_POST['block_id']  ?? '');
+$location  = trim($_POST['location']  ?? '');
+$areaHa    = is_numeric($_POST['area_ha'] ?? '') ? (float) $_POST['area_ha'] : 0;
+$gps       = trim($_POST['gps']       ?? '');
+$soilType  = trim($_POST['analysis_type'] ?? '');
+
+if ($name === '' || $blockId === '') {
+    $_SESSION['flash_error'] = 'Block ID and Block Name are required.';
+    header('Location: /dashboard/crop-cards/');
+    exit;
+}
+
+if ($action === 'create') {
+    $stmt = $pdo->prepare('
+        INSERT INTO block_info (modx_user_id, name, block_id, location, area, gps, status, date_added)
+        VALUES (?, ?, ?, ?, ?, ?, 0, CURDATE())
+    ');
+    $stmt->execute([$userId, $name, $blockId, $location, (int) $areaHa, $gps]);
+
+    $_SESSION['flash_success'] = 'Paddock "' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '" created.';
+    header('Location: /dashboard/crop-cards/');
+    exit;
+}
+
+if ($action === 'edit') {
+    $recordId = (int) ($_POST['record_id'] ?? 0);
+
+    if ($recordId <= 0) {
+        $_SESSION['flash_error'] = 'Invalid record.';
+        header('Location: /dashboard/crop-cards/');
+        exit;
+    }
+
+    // Ownership check
+    $check = $pdo->prepare('SELECT id FROM block_info WHERE id = ? AND modx_user_id = ? LIMIT 1');
+    $check->execute([$recordId, $userId]);
+    if (!$check->fetch()) {
+        $_SESSION['flash_error'] = 'Record not found or access denied.';
+        header('Location: /dashboard/crop-cards/');
+        exit;
+    }
+
+    $stmt = $pdo->prepare('
+        UPDATE block_info
+        SET name = ?, block_id = ?, location = ?, area = ?, gps = ?
+        WHERE id = ? AND modx_user_id = ?
+    ');
+    $stmt->execute([$name, $blockId, $location, (int) $areaHa, $gps, $recordId, $userId]);
+
+    $_SESSION['flash_success'] = 'Paddock "' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '" updated.';
+    header('Location: /dashboard/crop-cards/');
+    exit;
+}
+
+// Unknown action
+header('Location: /dashboard/crop-cards/');
+exit;

+ 482 - 790
dashboard/crop-cards/index.php

@@ -1,811 +1,503 @@
-<!doctype html>
-<html lang="en">
-
-<head>
-	<title>[[*longtitle]] | [[++site_name]]</title>
-	<base href="[[!++site_url]]">
-	<meta charset="[[++modx_charset]]">
-	<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
-	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
-	<meta name="keywords" content="[[*introtext]]">
-	<meta name="description" content="[[*description]]">
-	<link rel="icon" href="client-assets/images/favicon.ico?v=2" type="image/x-icon"> [[!Profile]]
-	
-	<script type="text/javascript">
-    	window.dataLayer = window.dataLayer || [];
-    
-    	function gtag() {
-    		dataLayer.push(arguments);
-    	}
-    	gtag('js', new Date());
-    	gtag('set', {
-    		'user_id': '[[+modx.user.id]]'
-    	}); // Set the user ID using signed-in user_id.
-    	gtag('config', 'UA-133963301-1');
-	</script>
-	
-	<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" />
-	<link href="client-assets/css/dashboard-2021.css" rel="stylesheet" />
-	<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/js/all.min.js" crossorigin="anonymous"></script>
-	<link href="https://cdn.datatables.net/1.10.20/css/dataTables.bootstrap4.min.css" rel="stylesheet" crossorigin="anonymous" />
-	<script src="client-assets/js/skycons.js"></script>
-	<style>
-    	.btn-append {
-    		color: #495057;
-    		background-color: #e9ecef;
-    		border: 1px solid #ced4da;
-    	}
-    	.footer {
-    		position: absolute;
-    		bottom: 0;
-    		width: 100%;
-    		height: 60px;
-    		line-height: 60px;
-    	}
-	</style>
-</head>
-
-<body class="sb-nav-fixed" id="page-top"> 
-    [[!Personalize?
-        &yesChunk=`navHeaderLogged`
-        &noChunk=`navHeader`
-        &allowedGroups=`basicClients,bacicAdmin,companyClients,companyManagers`
-    ]]
-    
-	<div id="layoutSidenav">
-	    <div id="layoutSidenav_nav">
-    		<!-- Sidebar -->
-    		[[Wayfinder?
-    		    &startId=`2` 
-        		&displayStart=`0` 
-        		&startitemTpl=`startitemTpl` 
-        		&selfClass=`show` 
-        		&level=`2`
-        		&outerTpl=`outer`
-        		    &outerClass=`sb-sidenav accordion sb-sidenav-dark`
-        		&rowTpl=`row`
-        		    &rowClass=`nav-link`
-        		&parentRowTpl=`parentRow`
-        		    &parentClass=`nav-link collapsed`
-        		&innerTpl=`inner`
-        		    &innerClass=`collapse`
-        		&innerRowTpl=`secondInner`
-        		    &innerRowClass=`nav-link`
-    		]]
-        </div>
-		
-		<div id="layoutSidenav_content">
-			<main>
-
-				<div class="container-fluid px-4">
-				    <h1 class="mt-4">[[*pagetitle]]</h1>
-
-					<ol class="breadcrumb mb-4"> [[$dash-breadcrumbs]] </ol>
-					
-					<div class="row">
-					    <div class="container-fluid">
-    <div class="row">
-        <div class="col">
-            <h2>[[*pagetitle]]</h2>
-        </div>
-    </div>
-	
-	<!--grid-->
-	<div class="row">
-		<div class="col-12 col-md-3">
-			
-			<div class="row">
-			    <div class="col">
-        			<form action="#" method="GET">
-        				<div class="input-group mb-3">
-        					<input type="text" class="form-control" aria-label="Recipient's username" aria-describedby="basic-addon2" placeholder="Search...">
-        					<div class="input-group-append">
-        						<span class="input-group-text" id="basic-addon2"><i class="fa fa-search"></i></span>
-        					</div>
-        				</div>
-        				<!-- Input Group -->
-        			</form>
-			    </div>
-			</div>
-			
-			<div class="row ">
-			    <div class="col">
-        			<div class="alert alert-danger" role="alert">
-        				<h3>[[*longtitle]]</h3>
-        			</div>
-        		</div>
-    		</div>
-
-            <div class="row ">
-			    <div class="col">
-        			<div class="list-group">
-        				<a href="#" class="list-group-item list-group-item-action"> Folders
-        				</a>
-        				<a href="#" class="list-group-item list-group-item-action list-group-item-light text-warning">
-        			    	<i class="fa fa-archive text-warning" aria-hidden="true"></i> Archived
-        				    <span class="badge badge-warning badge-pill float-right">[[!analysisCount? &analysis=`block_info` &cid=`[[+id]]` &status=`2` ]]</span>
-        				</a>
-        				<a href="#" class="list-group-item list-group-item-action list-group-item-light text-danger">
-        				    <i class="fa fa-trash text-danger" aria-hidden="true"></i> Deleted
-        				    <span class="badge badge-danger badge-pill float-right">[[!analysisCount? &analysis=`block_info` &cid=`[[+id]]` &status=`3` ]]</span>
-        				</a>
-        			</div>
-        		</div>
-        	</div>
-			
-		</div>
-
-    	<hr>
-    	
-    	<!-- tab content -->
-    	<div class="col-12 col-md-9 ">
-    			<!-- tab content -->
-    
-            
-    	    
-    	    <br>
-    	
-        	<div class="row">
-        		<div class="col">
-        			<h3>[[*longtitle]]</h3>
-        		</div>
-        	</div>
-        	
-        	<div class="row"> 
-        	<div class="col"> 
-        	<button type="button" class="btn btn-success" data-toggle="modal" data-target="#createPaddock">Create New Paddock</button> 
-        	<!-- Modal -->
-<div class="modal fade" id="createPaddock" tabindex="-1" role="dialog" aria-labelledby="createPaddock" aria-hidden="true">
-  <div class="modal-dialog modal-lg modal-dialog-centered" role="document">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h5 class="modal-title" id="exampleModalLabel">Create Paddock Record</h5>
-        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-          <span aria-hidden="true">&times;</span>
-        </button>
-      </div>
-      <div class="modal-body">
-          
-          <?php
-error_reporting(E_ALL);
-ini_set('display_errors', 1);
-
-if(isset($_POST['submit'])) {
-    
-    $sql = null;
-    //$con = mysqli_connect("localhost", "root", "R3M0T31", "cropmonitor");
-    $con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
-    
-    //set todays date
-    $date_added = date("Y-m-d H:i:s");
-    
-    //Get figures
-    $modx_user_id = (isset($_POST["m_user"])) ? $_POST["m_user"] : "";
-    
-    $client_name = (isset($_POST["name"])) ? $_POST["name"] : "";
-    $site_address = (isset($_POST["site_address"])) ? $_POST["site_address"] : "";
-    
-    $site_id = (isset($_POST["site_id"])) ? $_POST["site_id"] : "";
-    
-    $soil_type = (isset($_POST["analysis_type"])) ? $_POST["analysis_type"] : "";  //need to fix form to say soil_type not analysis_type
-    
-    
-    
-    /* ********* END ********* */
-    
-    // Check connection
-    if (mysqli_connect_errno()) {
-        echo "Failed to connect to MySQL: " . mysqli_connect_error();
-    }
-    		
-    $sql = mysqli_query($con, "INSERT into `block_info`
-                (
-                    modx_user_id,
-                    date_added,
-                    area,
-                    block_id
-                ) VALUES (
-                    '" . $modx_user_id . "',
-                    '" . $date_added . "',
-                    '" . $area . "',
-                    '" . $block_id . "'
-                )" );
-    
-    $insert_id = mysqli_insert_id($con);
-    
-                
-    if ($sql === TRUE)
-    	{
-    	//echo "success"; //CHECKING
-    	// forward to results page if successfully inserts to database  [[~32]]
-    	echo "";
-        } else {
-        die(mysqli_error($con)); // TODO: better error handling
-        //echo "User Profile incorrect";
-    }
-}
-?>
-          
-          <form method="post" action="[~[*id*]~]" id="createPaddock" novalidate>
-              
-              <input type="text" class="form-control" id="modx_user" value="[[+user]]" hidden>
-              <input type="text" class="form-control" id="mid" value="[[+id]]" hidden>
-              
-              <h6>Block Identification</h6>
-              <div class="form-row">
-                  <div class="col">
-                    <label for="exampleInputEmail1">Block ID</label>
-                    <input type="text" class="form-control form-control-sm" id="id" aria-describedby="idHelp" placeholder="Block Id" required>
-                    <small id="emailHelp" class="form-text text-muted"></small>
-                    <div class="valid-feedback">Looks good!</div>
-                  </div>
-                  <div class="col">
-                    <label for="exampleInputEmail1">Block Name</label>
-                    <input type="text" class="form-control form-control-sm" id="name" aria-describedby="idHelp" placeholder="Block Name" required>
-                    <small id="emailHelp" class="form-text text-muted"></small>
-                  </div>
-              </div>
-              
-              <hr>
-              <h6>Location / Sizing</h6>
-              <div class="form-group">
-                <label for="exampleInputPassword1">Location</label>
-                <input type="text" class="form-control form-control-sm" id="location" placeholder="Block Address">
-              </div>
-              
-              <div class="form-row">
-                  <div class="col">
-                    <label for="exampleInputEmail1">Area</label>
-                    <input type="number" class="form-control form-control-sm" id="area_ha" aria-describedby="areaHelp" placeholder="Block Size" oninput="areaConverter(this.id,this.value)" onchange="areaConverter(this.value)">
-                    <small id="areaHelp" class="form-text text-muted">in hectare's</small>
-                  </div>
-                  <div class="col">
-                    <label for="exampleInputEmail1">Area</label>
-                    <input type="number" class="form-control form-control-sm" id="area_ac" aria-describedby="areaHelp" placeholder="Block Size" oninput="areaConverter(this.id,this.value)" onchange="areaConverter(this.value)">
-                    <small id="areaHelp" class="form-text text-muted">in acre's</small>
-                  </div>
-                  <div class="col">
-                    <label for="exampleInputEmail1">Block Name</label>
-                    <input type="text" class="form-control form-control-sm" id="name" aria-describedby="idHelp" placeholder="Block Name">
-                    <small id="emailHelp" class="form-text text-muted"></small>
-                  </div>
-              </div>
-              
-              <script>
-            	function areaConverter(source,valNum) {
-            		valNum = parseFloat(valNum);
-            		var area_ha = document.getElementById("area_ha");
-            		var area_ac = document.getElementById("area_ac");
-            		
-            		if (source=="area_ha") {
-            			area_ac.value=(valNum/0.404686).toFixed(2);
-            		}
-            		if (source=="area_ac") {
-            			area_ha.value=(valNum/2.4710559990832).toFixed(2);
-            		}
-            	}
-              </script>
-              
-              <hr>
-              <h6>Soil Clasification</h6>
-              <div class="form-row">
-                  <div class="col">
-                    <label for="exampleInputEmail1">Area</label>
-                    <select class="form-control form-control-sm" name="analysis_type" id="analysis_type" required>
-                        <option>Select the type of soil...</option>
-                        <option id="sandy">sandy</option>
-                        <option id="light">light</option>
-                        <option id="medium">medium</option>
-                        <option id="heavy">heavy</option>
-                    </select>
-                  </div>
-                  <div class="col">
-                    <label for="exampleInputEmail1">Block Name</label>
-                    <input type="text" class="form-control form-control-sm" id="name" aria-describedby="idHelp" placeholder="Block Name">
-                    <small id="emailHelp" class="form-text text-muted"></small>
-                  </div>
-              </div>
-
-            
-      </div>
-      <div class="modal-footer">
-        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-        <button form="createPaddock" type="submit" class="btn btn-success">Save changes</button>
-        </form>
-      </div>
-    </div>
-  </div>
-</div>
-
-        	</div> 
-        	</div> 
-        	<br> 
-
-
-        	<div class="row">
-        		<div class="col">
-            		<div class="d-none d-md-block "> <!-- d-lg-none -->
-            		    <div class='form-row'>
-                            <div class='col-md-1'><input type='text' readonly class='text-center form-control-plaintext font-weight-bold' placeholder='ID' ></div>
-                            <div class='col-md-1'><input type='text' readonly class='text-center form-control-plaintext font-weight-bold' placeholder='Edit' ></div>
-                            <div class='col'><input type='text' readonly class='text-center form-control-plaintext font-weight-bold' placeholder='Name' ></div>
-                            <div class='col-md-1'><input type='text' readonly class='text-center form-control-plaintext font-weight-bold' placeholder='Size' ></div>
-                            <div class='col-md-2'><input type='text' readonly class='text-center form-control-plaintext font-weight-bold' placeholder='Location' ></div>
-                            <div class='col-md-2'><input type='text' readonly class='text-center form-control-plaintext font-weight-bold' placeholder='Current Crop' ></div>
-                            <div class='col-md-1'><input type='text' readonly class='text-center form-control-plaintext font-weight-bold' placeholder='Status' ></div>
-                            <div class='col-md-1'><input type='text' readonly class='text-center form-control-plaintext font-weight-bold' placeholder='Actions' ></div>
-                        </div>
-                    </div>
-                
-                /*[[!blockIdentification? &cid=`[[+id]]` ]]*/
-				<?php
-if ($cid) {
-     $client_id = $cid; //  client number
-} else {
-    $client_id = '2'; // client number
+<?php
+require_once __DIR__ . '/../../config/database.php';
+require_once __DIR__ . '/../../lib/auth.php';
+require_once __DIR__ . '/../../lib/csrf.php';
+
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
 }
 
-$client_id = '2'; // client number
+requireLogin();
 
-$analysisType = $analysis;
-$icon = $icon;
+$pageTitle = 'Crop Cards';
+$siteName  = 'Crop Monitor';
 
-/*
-Status Table
-0 = Blank
-1 = Read
-2 = Archived
-3 = Deleted
-*/
+$pdo    = getDBConnection();
+$userId = getCurrentUserId();
 
-//Database connection
-//$con = mysqli_connect("localhost", "root", "R3M0T31", "cropmonitor");
-$con = mysqli_connect("localhost", "cropmonitor", "brvnCcaEYxlPCS3", "cropmonitor");
+// ── Block counts for sidebar badges ──────────────────────────────────────────
+$stmtArchived = $pdo->prepare(
+    'SELECT COUNT(*) FROM block_info WHERE modx_user_id = ? AND status = 2'
+);
+$stmtArchived->execute([$userId]);
+$archivedCount = (int) $stmtArchived->fetchColumn();
 
-// Check connection
-if (mysqli_connect_errno()) {
-    echo "Failed to connect to MySQL: " . mysqli_connect_error();
-}
+$stmtDeleted = $pdo->prepare(
+    'SELECT COUNT(*) FROM block_info WHERE modx_user_id = ? AND status = 3'
+);
+$stmtDeleted->execute([$userId]);
+$deletedCount = (int) $stmtDeleted->fetchColumn();
 
-// Get results from database 
-$result = mysqli_query($con, "SELECT * FROM `block_info` WHERE `modx_user_id` = ". $client_id ." AND `status` <= 1 "); //
-                                 //
-//plant_records.crop_type, plant_specifications.plant_type, plant_specifications.N_Min, plant_specifications.N_Max, plant_records.N, plant_records.id
-// mysqli_query returns false if something went wrong with the query
-
-if ($result === FALSE) {
-    die(mysqli_error($con)); // TODO: better error handling
-    echo "User Profile incorrect";
-    
-} else {
-    $i = 1;
-    while ($row = mysqli_fetch_array($result)) {
-    
-        $rowid = $row['id'];
-        $name = $row['name'];
-        $block = $row['block_id'];
-        $location = $row['location'];
-        $area = $row['area'];
-            $area_ha = number_format($area,1);
-            $area_ac = number_format(($area * 2.47105),1);
-            $area_value = $area_ha . "ha - " . $area_ac . "acres";
-        $gps = $row['gps'];
-        $status = $row['status'];
-        
-        $currentCrop = '';
-        
-        /* Status Table */
-        if ($row['status'] == 0 ) { // 0 = Blank
-            $colour = 'table-secondary';
-        } else if ($row['status'] == 1 ) { //1 = Read
-            $colour = '';
-        } else if ($row['status'] == 2 ) { //2 = Archived
-            $colour = '';
-        } else if ($row['status'] == 3 ) { //3 = Deleted
-            $colour = '';
-        } else {
-            $colour = '';
-        }
-        
-        //$today = date('dS l M y');
-        //$filename = $row['rand'] . " - Soil-Analysis - " . $today;
-        
-        echo "<div class='row mb-2'>";
-        echo "<div class='col border border-success rounded p-1'>";
-        echo "<div class='form-row m-1'>";
-            echo "<div class='text-left font-weight-bold' ><p>$i</p></div>"; //<label for=''>ID</label>   d-none d-md-block d-lg-none
-            echo "<div class='col-6 col-sm-11 col-md-2'>";
-                echo "<div class='row'>";
-                    echo "<div class='col-6 col-md-6'><a class='text-left font-weight-bold btn btn-primary btn-sm btn-block' href='[[~93]]?rid=$rowid&id=$block&block=$name'><i class='fas fa-globe-asia fa-1x text-white' aria-hidden='true'></i></a></div>";
-                    echo "<div class='col-6 col-md-6'><button type='submit' class='text-left font-weight-bold btn btn-success btn-sm btn-block ' data-toggle='modal' data-target='#editPaddock$rowid'><i class='far fa-edit'></i>  " . $block . "</button></div>";
-                echo "</div>"; //<label for=''>Block</label>
-            echo "</div>";
-            echo "<div class='col'><label class='form-label form-label-sm m-0 d-block d-sm-none' for=''>Name</label><input type='text' class='form-control form-control-sm' value='$name'></div>";    //<label for=''>Name</label>
-            echo "<div class='col-md-1'><label class='form-label form-label-sm m-0 d-block d-sm-none' for=''>Size</label><input type='text' class='form-control form-control-sm text-center' value='$area_value'></div>";    //<label for=''>Size</label>
-            echo "<div class='col-md-2'><label class='form-label form-label-sm m-0 d-block d-sm-none' for=''>Location</label><input type='text' class='form-control form-control-sm' value='$location'></div>";    //<label for=''>Location</label>
-            echo "<div class='col-md-2'><label class='form-label form-label-sm m-0 d-block d-sm-none' for=''>Current Crop</label><input type='text' class='form-control form-control-sm' value='$currentCrop'></div>";    //<label for=''>Location</label>
-            echo "<div class='col-md-1'><label class='form-label form-label-sm m-0 d-block d-sm-none' for=''>Location</label><input type='text' readonly class='form-control form-control-plaintext form-control-sm' value='$status'></div>";    //<label for=''>Location</label>
-            echo "<div class='col-md-1'><label class='form-label form-label-sm m-0 d-block d-sm-none' for=''>Actions</label>";
-                echo "<a href='#' target='_blank' data-toggle='tooltip' data-placement='top' title='Delete Block'><i class='fa fa-trash text-danger' aria-hidden='true'></i>  ";
-                echo "<a href='#' target='_blank' data-toggle='tooltip' data-placement='top' title='Archive Block'><i class='fa fa-archive text-warning' aria-hidden='true'></i>  ";
-                echo "<a href='#' target='_blank' data-toggle='tooltip' data-placement='top' title='Reply to Client'><i class='text-success fa fa-reply' aria-hidden='true'></i>  ";
-                echo "<a href='#' target='_blank' data-toggle='tooltip' data-placement='top' title='Share Report'><i class='text-success fa fa-share' aria-hidden='true'></i></a>  ";
-                echo "<a href='#' target='_blank' data-toggle='tooltip' data-placement='top' title='Download Report'><i class='text-dark fas fa-cloud-download-alt'></i></a>";
-            echo "</div>";
-        echo "</div>";
-        echo "</div>";
-        echo "</div>";
-    
-    ?>
-   
-    <!-- ********************************************************* Modal ********************************************************* -->
-    <div class="modal fade" id="editPaddock<?php echo $rowid; ?>" tabindex="-1" role="dialog" aria-labelledby="editPaddock<?php echo $rowid; ?>" aria-hidden="true">
-      <div class="modal-dialog modal-lg modal-dialog-centered" role="document">
-        <div class="modal-content">
-          <div class="modal-header">
-            <h5 class="modal-title" id="exampleModalLabel">Edit Paddock Record</h5>
-            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-              <span aria-hidden="true">&times;</span>
-            </button>
-          </div>
-          <div class="modal-body">
-              
-              [[!createBlockSubmit]]
-              
-              <form method="post" action="[~[*id*]~]" id="editPaddock<?php echo $rowid; ?>" novalidate>
-                  
-                  <input type="text" class="form-control" id="modx_user" value="<?php echo $rowid; ?>" hidden>
-                  <input type="text" class="form-control" id="mid" value="[[+id]]" hidden>
-                  
-                  <div class="form-row">
-                      <div class="col">
-                        <label for="exampleInputEmail1">Block ID</label>
-                        <input type="text" class="form-control form-control-sm" id="block_id" aria-describedby="block_idHelp" value="<?php echo $block; ?>" required>
-                        <small id="block_idHelp" class="form-text text-muted"></small>
-                        <div class="valid-feedback">Looks good!</div>
-                      </div>
-                      <div class="col">
-                        <label for="exampleInputEmail1">Block Name</label>
-                        <input type="text" class="form-control form-control-sm" id="name" aria-describedby="nameHelp" value="<?php echo $name; ?>" required>
-                        <small id="nameHelp" class="form-text text-muted"></small>
-                      </div>
-                  </div>
-                  
-                  <hr>
-                  <h6>Location / Sizing</h6>
-                  <div class="form-group">
-                    <label for="exampleInputPassword1">Location</label>
-                    <input type="text" class="form-control form-control-sm" id="location" value="<?php echo $location; ?>" >
-                  </div>
-                  
-                  <div class="form-row">
-                      <div class="col">
-                        <label for="exampleInputEmail1">Area</label>
-                        <input type="text" class="form-control form-control-sm" id="area_ha" aria-describedby="areahaHelp" value="<?php echo $area_ha; ?>" oninput="areaConverter(this.id,this.value)" onchange="areaConverter(this.value)">
-                        <small id="areahaHelp" class="form-text text-muted">in hectare's</small>
-                      </div>
-                      <div class="col">
-                        <label for="exampleInputEmail1">Area</label>
-                        <input type="text" class="form-control form-control-sm" id="area_ac" aria-describedby="areaacHelp" value="<?php echo $area_ac; ?>" oninput="areaConverter(this.id,this.value)" onchange="areaConverter(this.value)">
-                        <small id="areaaHelp" class="form-text text-muted">in acre's</small>
-                      </div>
-                      <div class="col">
-                        <label for="exampleInputEmail1">GPS</label>
-                        <input type="text" class="form-control form-control-sm" id="gps" aria-describedby="gpsHelp" value="<?php echo $gps; ?>" >
-                        <small id="gpsHelp" class="form-text text-muted"></small>
-                      </div>
-                  </div>
-                  
-                  <script>
-                	function areaConverter(source,valNum) {
-                		valNum = parseFloat(valNum);
-                		var area_ha = document.getElementById("area_ha");
-                		var area_ac = document.getElementById("area_ac");
-                		
-                		if (source=="area_ha") {
-                			area_ac.value=(valNum/0.404686).toFixed(2);
-                		}
-                		if (source=="area_ac") {
-                			area_ha.value=(valNum/2.4710559990832).toFixed(2);
-                		}
-                	}
-                  </script>
-                  
-                  <hr>
-                  <h6>Soil Clasification</h6>
-                  <div class="form-row">
-                      <div class="col">
-                        <label for="exampleInputEmail1">Area</label>
-                        <select class="form-control form-control-sm" name="analysis_type" id="analysis_type" required>
-                            <option>Select the type of soil...</option>
-                            <option id="sandy">sandy</option>
-                            <option id="light">light</option>
-                            <option id="medium">medium</option>
-                            <option id="heavy">heavy</option>
-                        </select>
-                      </div>
-                      <div class="col">
-                        <label for="exampleInputEmail1">Block Name</label>
-                        <input type="text" class="form-control form-control-sm" id="name" aria-describedby="idHelp" placeholder="Block Name">
-                        <small id="emailHelp" class="form-text text-muted"></small>
-                      </div>
-                  </div>
-                  
-                  <hr>
-                  <h6>Current Crop Details</h6>
-                  <div class="form-row">
-                      <div class="col">
-                        <label for="exampleInputEmail1">Block Name</label>
-                        <input type="text" class="form-control form-control-sm" id="name" aria-describedby="idHelp" placeholder="Block Name">
-                        <small id="emailHelp" class="form-text text-muted"></small>
-                      </div>
-                      <div class="col">
-                        <label for="exampleInputEmail1">Block Name</label>
-                        <input type="text" class="form-control form-control-sm" id="name" aria-describedby="idHelp" placeholder="Block Name">
-                        <small id="emailHelp" class="form-text text-muted"></small>
-                      </div>
-                      <div class="col">
-                        <label for="exampleInputEmail1">Block Name</label>
-                        <input type="text" class="form-control form-control-sm" id="name" aria-describedby="idHelp" placeholder="Block Name">
-                        <small id="emailHelp" class="form-text text-muted"></small>
-                      </div>
-                  </div>
-    
-                
-          </div>
-          <div class="modal-footer">
-            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
-            <button form="editPaddock<?php echo $rowid; ?>" type="submit" class="btn btn-success">Save changes</button>
-            </form>
-          </div>
-        </div>
-      </div>
-    </div>
+// ── Block list (status 0 = new, 1 = active) ───────────────────────────────
+$stmtBlocks = $pdo->prepare(
+    'SELECT * FROM block_info WHERE modx_user_id = ? AND status <= 1 ORDER BY id ASC'
+);
+$stmtBlocks->execute([$userId]);
+$blocks = $stmtBlocks->fetchAll();
 
+// ── Flash messages ────────────────────────────────────────────────────────
+$flashSuccess = $_SESSION['flash_success'] ?? null;
+$flashError   = $_SESSION['flash_error']   ?? null;
+unset($_SESSION['flash_success'], $_SESSION['flash_error']);
 
-<?php
-     $i++;
-    }
-}
+$h = fn($v) => htmlspecialchars((string) $v, ENT_QUOTES, 'UTF-8');
 
-mysqli_close($con);
+include __DIR__ . '/../../layouts/header.php';
+include __DIR__ . '/../../layouts/navbar.php';
 ?>
-                
-                </div>
-    	    </div>
-        </div>
-    
-    </div>
-</div>
 
+<div id="layoutSidenav">
+    <div id="layoutSidenav_nav">
+        <?php include __DIR__ . '/../../layouts/sidebar.php'; ?>
+    </div>
+    <div id="layoutSidenav_content">
+        <main>
+            <div class="container-fluid px-4">
 
+                <h1 class="mt-4"><?= $h($pageTitle) ?></h1>
+                <ol class="breadcrumb mb-4">
+                    <li class="breadcrumb-item"><a href="/dashboard/dashboard.php">Dashboard</a></li>
+                    <li class="breadcrumb-item active">Crop Cards</li>
+                </ol>
 
-<div class="container-fluid">
-    <div class="row clearfix ">
-        <div class="col border border-success rounded shadow">
-            <form>
-                <div class="form-row">
-                    <div class="form-group col-3">
-                        <label for="farm_name">Farm Name</label>
-                        <input type="text" class="form-control" for="farm_name" placeholder="" readonly></input>
-                        <small id="farm_name" class="form-text text-muted"></small>
-                    </div>
-                    <div class="form-group col-3">
-                        <label for="paddock_name">Paddock Name</label>
-                        <input type="text" class="form-control" for="paddock_name" placeholder="" readonly></input>
-                        <small id="paddock_name" class="form-text text-muted"></small>
+                <?php if ($flashSuccess): ?>
+                    <div class="alert alert-success alert-dismissible fade show" role="alert">
+                        <?= $h($flashSuccess) ?>
+                        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
                     </div>
-                    <div class="form-group col-3">
-                        <label for="crop_name">Crop Name</label>
-                        <input type="text" class="form-control" for="crop_name" placeholder="" readonly></input>
-                        <small id="crop_name" class="form-text text-muted"></small>
+                <?php endif; ?>
+                <?php if ($flashError): ?>
+                    <div class="alert alert-danger alert-dismissible fade show" role="alert">
+                        <?= $h($flashError) ?>
+                        <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
                     </div>
-                    
-                    <div class="form-group col-3">
-                        <label for="paddock_area">Area</label>
-                        <input type="text" class="form-control" for="paddock_area" placeholder="" readonly></input>
-                        <small id="paddock_area" class="form-text text-muted"></small>
-                    </div>
-                </div>
-            </form>
-        </div>
-    </div>
-    
-    <div class="row clearfix">
-        <div class="col">
-            <br>
-            <h3>Crop Information</h3>
-        </div>
-    </div>
-        
-    <div class="row clearfix">
-        <div class="col-4 ">
-            <div class="card">
-                <div class="card-header">
-                    <h4>Current Alerts</h4>
-                </div>
-                <div class="card-body">
-                    <div class="table-responsive table-editable">
-                        <span class="table-add float-right mb-3 mr-2"><a href="#!" class="text-success"><i class="fas fa-plus fa-2x" aria-hidden="true"></i></a></span>
-                        <table class="table table-striped table-hover">
-                            <thead class="table-danger">
-                            <tr>
-                              <th scope="col">#</th>
-                              <th scope="col">First</th>
-                              <th scope="col">Last</th>
-                              <th scope="col">Handle</th>
-                            </tr>
-                            </thead>
-                            <tbody>
-                            <tr>
-                              <th scope="row">1</th>
-                              <td>Mark</td>
-                              <td>Otto</td>
-                              <td>@mdo</td>
-                            </tr>
-                            <tr>
-                              <th scope="row">2</th>
-                              <td>Jacob</td>
-                              <td>Thornton</td>
-                              <td>@fat</td>
-                            </tr>
-                            <tr>
-                              <th scope="row">3</th>
-                              <td>Larry</td>
-                              <td>the Bird</td>
-                              <td>@twitter</td>
-                            </tr>
-                            </tbody>
-                        </table>
+                <?php endif; ?>
+
+                <div class="row">
+
+                    <!-- ── Left sidebar panel ──────────────────────────────── -->
+                    <div class="col-12 col-md-3">
+
+                        <div class="row mb-3">
+                            <div class="col">
+                                <form action="" method="GET">
+                                    <div class="input-group">
+                                        <input type="text" class="form-control" name="q"
+                                               placeholder="Search..."
+                                               value="<?= $h($_GET['q'] ?? '') ?>">
+                                        <span class="input-group-text"><i class="fa fa-search"></i></span>
+                                    </div>
+                                </form>
+                            </div>
+                        </div>
+
+                        <div class="row mb-3">
+                            <div class="col">
+                                <div class="alert alert-danger">
+                                    <h5 class="mb-0"><?= $h($pageTitle) ?></h5>
+                                </div>
+                            </div>
+                        </div>
+
+                        <div class="row">
+                            <div class="col">
+                                <div class="list-group">
+                                    <a href="#" class="list-group-item list-group-item-action fw-bold">
+                                        Folders
+                                    </a>
+                                    <a href="#" class="list-group-item list-group-item-action list-group-item-light text-warning">
+                                        <i class="fa fa-archive text-warning"></i> Archived
+                                        <span class="badge bg-warning text-dark float-end"><?= $archivedCount ?></span>
+                                    </a>
+                                    <a href="#" class="list-group-item list-group-item-action list-group-item-light text-danger">
+                                        <i class="fa fa-trash text-danger"></i> Deleted
+                                        <span class="badge bg-danger float-end"><?= $deletedCount ?></span>
+                                    </a>
+                                </div>
+                            </div>
+                        </div>
+
+                    </div><!-- /col: left panel -->
+
+                    <!-- ── Block list ───────────────────────────────────────── -->
+                    <div class="col-12 col-md-9">
+
+                        <div class="row mb-3">
+                            <div class="col">
+                                <button type="button" class="btn btn-success"
+                                        data-bs-toggle="modal" data-bs-target="#createPaddock">
+                                    <i class="fas fa-plus me-1"></i>Create New Paddock
+                                </button>
+                            </div>
+                        </div>
+
+                        <!-- Column headers (desktop only) -->
+                        <div class="d-none d-md-block mb-1">
+                            <div class="row fw-bold text-center text-muted small">
+                                <div class="col-md-1">ID</div>
+                                <div class="col-md-2">Block</div>
+                                <div class="col">Name</div>
+                                <div class="col-md-1">Size</div>
+                                <div class="col-md-2">Location</div>
+                                <div class="col-md-2">Current Crop</div>
+                                <div class="col-md-1">Status</div>
+                                <div class="col-md-1">Actions</div>
+                            </div>
+                        </div>
+
+                        <?php if (empty($blocks)): ?>
+                            <div class="alert alert-info">No paddock records found. Create your first paddock above.</div>
+                        <?php endif; ?>
+
+                        <?php foreach ($blocks as $i => $row):
+                            $rowid    = (int) $row['id'];
+                            $areaHa   = number_format((float) $row['area'], 1);
+                            $areaAc   = number_format((float) $row['area'] * 2.47105, 1);
+                            $areaDisp = $areaHa . ' ha – ' . $areaAc . ' ac';
+                        ?>
+                        <div class="row mb-2">
+                            <div class="col border border-success rounded p-2">
+                                <div class="row align-items-center">
+                                    <div class="col-md-1 text-center fw-bold"><?= $i + 1 ?></div>
+                                    <div class="col-6 col-sm-11 col-md-2">
+                                        <div class="row g-1">
+                                            <div class="col-6">
+                                                <a class="btn btn-primary btn-sm w-100"
+                                                   href="/dashboard/crop-cards/block-detail.php?rid=<?= $rowid ?>&id=<?= $h($row['block_id']) ?>&block=<?= urlencode($row['name'] ?? '') ?>"
+                                                   title="View block">
+                                                    <i class="fas fa-globe-asia text-white"></i>
+                                                </a>
+                                            </div>
+                                            <div class="col-6">
+                                                <button type="button"
+                                                        class="btn btn-success btn-sm w-100"
+                                                        data-bs-toggle="modal"
+                                                        data-bs-target="#editPaddock<?= $rowid ?>">
+                                                    <i class="far fa-edit"></i> <?= $h($row['block_id']) ?>
+                                                </button>
+                                            </div>
+                                        </div>
+                                    </div>
+                                    <div class="col">
+                                        <label class="form-label form-label-sm mb-0 d-block d-sm-none">Name</label>
+                                        <input type="text" class="form-control form-control-sm"
+                                               value="<?= $h($row['name']) ?>" readonly>
+                                    </div>
+                                    <div class="col-md-1">
+                                        <label class="form-label form-label-sm mb-0 d-block d-sm-none">Size</label>
+                                        <input type="text" class="form-control form-control-sm text-center"
+                                               value="<?= $h($areaDisp) ?>" readonly>
+                                    </div>
+                                    <div class="col-md-2">
+                                        <label class="form-label form-label-sm mb-0 d-block d-sm-none">Location</label>
+                                        <input type="text" class="form-control form-control-sm"
+                                               value="<?= $h($row['location']) ?>" readonly>
+                                    </div>
+                                    <div class="col-md-2">
+                                        <label class="form-label form-label-sm mb-0 d-block d-sm-none">Current Crop</label>
+                                        <input type="text" class="form-control form-control-sm" value="" readonly>
+                                    </div>
+                                    <div class="col-md-1">
+                                        <label class="form-label form-label-sm mb-0 d-block d-sm-none">Status</label>
+                                        <input type="text" class="form-control form-control-plaintext form-control-sm text-center"
+                                               value="<?= $h($row['status']) ?>" readonly>
+                                    </div>
+                                    <div class="col-md-1">
+                                        <label class="form-label form-label-sm mb-0 d-block d-sm-none">Actions</label>
+                                        <a href="#" title="Delete Block"><i class="fa fa-trash text-danger"></i></a>&nbsp;
+                                        <a href="#" title="Archive Block"><i class="fa fa-archive text-warning"></i></a>&nbsp;
+                                        <a href="#" title="Reply to Client"><i class="fa fa-reply text-success"></i></a>&nbsp;
+                                        <a href="#" title="Share Report"><i class="fa fa-share text-success"></i></a>&nbsp;
+                                        <a href="#" title="Download Report"><i class="fas fa-cloud-download-alt text-dark"></i></a>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+
+                        <!-- Edit Paddock modal -->
+                        <div class="modal fade" id="editPaddock<?= $rowid ?>" tabindex="-1"
+                             aria-labelledby="editPaddock<?= $rowid ?>Label" aria-hidden="true">
+                            <div class="modal-dialog modal-lg modal-dialog-centered">
+                                <div class="modal-content">
+                                    <div class="modal-header">
+                                        <h5 class="modal-title" id="editPaddock<?= $rowid ?>Label">
+                                            Edit Paddock — <?= $h($row['name']) ?>
+                                        </h5>
+                                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
+                                    </div>
+                                    <form method="post" action="/controllers/blockSubmit.php"
+                                          id="editPaddockForm<?= $rowid ?>">
+                                        <div class="modal-body">
+                                            <input type="hidden" name="csrf_token"
+                                                   value="<?= $h(generateCsrfToken()) ?>">
+                                            <input type="hidden" name="action"    value="edit">
+                                            <input type="hidden" name="record_id" value="<?= $rowid ?>">
+
+                                            <div class="row mb-3">
+                                                <div class="col">
+                                                    <label class="form-label">Block ID</label>
+                                                    <input type="text" class="form-control form-control-sm"
+                                                           name="block_id" value="<?= $h($row['block_id']) ?>" required>
+                                                </div>
+                                                <div class="col">
+                                                    <label class="form-label">Block Name</label>
+                                                    <input type="text" class="form-control form-control-sm"
+                                                           name="name" value="<?= $h($row['name']) ?>" required>
+                                                </div>
+                                            </div>
+
+                                            <hr>
+                                            <h6>Location / Sizing</h6>
+
+                                            <div class="mb-3">
+                                                <label class="form-label">Location</label>
+                                                <input type="text" class="form-control form-control-sm"
+                                                       name="location" value="<?= $h($row['location']) ?>">
+                                            </div>
+
+                                            <div class="row mb-3">
+                                                <div class="col">
+                                                    <label class="form-label">Area (hectares)</label>
+                                                    <input type="number" step="0.01" class="form-control form-control-sm"
+                                                           id="edit_area_ha_<?= $rowid ?>" name="area_ha"
+                                                           value="<?= $h(number_format((float) $row['area'], 2)) ?>"
+                                                           oninput="areaConverter('area_ha',this.value,'<?= $rowid ?>')">
+                                                    <div class="form-text">in hectares</div>
+                                                </div>
+                                                <div class="col">
+                                                    <label class="form-label">Area (acres)</label>
+                                                    <input type="number" step="0.01" class="form-control form-control-sm"
+                                                           id="edit_area_ac_<?= $rowid ?>"
+                                                           value="<?= $h(number_format((float) $row['area'] * 2.47105, 2)) ?>"
+                                                           oninput="areaConverter('area_ac',this.value,'<?= $rowid ?>')">
+                                                    <div class="form-text">in acres</div>
+                                                </div>
+                                                <div class="col">
+                                                    <label class="form-label">GPS</label>
+                                                    <input type="text" class="form-control form-control-sm"
+                                                           name="gps" value="<?= $h($row['gps']) ?>">
+                                                </div>
+                                            </div>
+
+                                            <hr>
+                                            <h6>Soil Classification</h6>
+                                            <div class="row">
+                                                <div class="col">
+                                                    <label class="form-label">Soil Type</label>
+                                                    <select class="form-select form-select-sm" name="analysis_type">
+                                                        <option value="">Select soil type...</option>
+                                                        <option value="sandy">Sandy</option>
+                                                        <option value="light">Light</option>
+                                                        <option value="medium">Medium</option>
+                                                        <option value="heavy">Heavy</option>
+                                                    </select>
+                                                </div>
+                                            </div>
+
+                                        </div><!-- /modal-body -->
+                                        <div class="modal-footer">
+                                            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
+                                            <button type="submit" class="btn btn-success">Save Changes</button>
+                                        </div>
+                                    </form>
+                                </div>
+                            </div>
+                        </div><!-- /editPaddock modal -->
+
+                        <?php endforeach; ?>
+
+                    </div><!-- /col: block list -->
+
+                </div><!-- /row: main content -->
+
+                <!-- ── Crop Information summary (placeholder) ─────────────── -->
+                <div class="container-fluid mt-4">
+                    <div class="row mb-3">
+                        <div class="col">
+                            <div class="card border-success">
+                                <div class="card-body py-2">
+                                    <div class="row">
+                                        <div class="col-3">
+                                            <label class="form-label small mb-0">Farm Name</label>
+                                            <input type="text" class="form-control form-control-sm" readonly>
+                                        </div>
+                                        <div class="col-3">
+                                            <label class="form-label small mb-0">Paddock Name</label>
+                                            <input type="text" class="form-control form-control-sm" readonly>
+                                        </div>
+                                        <div class="col-3">
+                                            <label class="form-label small mb-0">Crop Name</label>
+                                            <input type="text" class="form-control form-control-sm" readonly>
+                                        </div>
+                                        <div class="col-3">
+                                            <label class="form-label small mb-0">Area</label>
+                                            <input type="text" class="form-control form-control-sm" readonly>
+                                        </div>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
                     </div>
-                </div>
-            </div>
-        </div>
-        
-        <div class="col-4 ">
-            <div class="card">
-                <div class="card-header">
-                    <h4>Fertiliser and Disease Control</h4>
-                </div>
-                <div class="card-body">
-                    <div class="table-responsive table-editable">
-                        <span class="table-add float-right mb-3 mr-2"><a href="#!" class="text-success"><i class="fas fa-plus fa-2x" aria-hidden="true"></i></a></span>
-                        <table class="table table-striped table-hover">
-                            <thead class="table-success">
-                            <tr>
-                              <th scope="col">#</th>
-                              <th scope="col">First</th>
-                              <th scope="col">Last</th>
-                              <th scope="col">Handle</th>
-                            </tr>
-                            </thead>
-                            <tbody>
-                            <tr>
-                              <th scope="row">1</th>
-                              <td>Mark</td>
-                              <td>Otto</td>
-                              <td>@mdo</td>
-                            </tr>
-                            <tr>
-                              <th scope="row">2</th>
-                              <td>Jacob</td>
-                              <td>Thornton</td>
-                              <td>@fat</td>
-                            </tr>
-                            <tr>
-                              <th scope="row">3</th>
-                              <td>Larry</td>
-                              <td>the Bird</td>
-                              <td>@twitter</td>
-                            </tr>
-                            </tbody>
-                        </table>
+
+                    <h4>Crop Information</h4>
+
+                    <div class="row">
+                        <div class="col-4">
+                            <div class="card">
+                                <div class="card-header"><h5 class="mb-0">Current Alerts</h5></div>
+                                <div class="card-body p-0">
+                                    <table class="table table-striped table-hover mb-0">
+                                        <thead class="table-danger">
+                                            <tr><th>#</th><th>Alert</th><th>Level</th></tr>
+                                        </thead>
+                                        <tbody>
+                                            <tr><td colspan="3" class="text-muted text-center">No alerts</td></tr>
+                                        </tbody>
+                                    </table>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="col-4">
+                            <div class="card">
+                                <div class="card-header"><h5 class="mb-0">Fertiliser &amp; Disease Control</h5></div>
+                                <div class="card-body p-0">
+                                    <table class="table table-striped table-hover mb-0">
+                                        <thead class="table-success">
+                                            <tr><th>#</th><th>Product</th><th>Date</th></tr>
+                                        </thead>
+                                        <tbody>
+                                            <tr><td colspan="3" class="text-muted text-center">No records</td></tr>
+                                        </tbody>
+                                    </table>
+                                </div>
+                            </div>
+                        </div>
+                        <div class="col-4">
+                            <div class="card">
+                                <div class="card-header"><h5 class="mb-0">Irrigation &amp; Weather</h5></div>
+                                <div class="card-body p-0">
+                                    <table class="table table-striped table-hover mb-0">
+                                        <thead class="table-warning">
+                                            <tr><th>#</th><th>Event</th><th>Date</th></tr>
+                                        </thead>
+                                        <tbody>
+                                            <tr><td colspan="3" class="text-muted text-center">No records</td></tr>
+                                        </tbody>
+                                    </table>
+                                </div>
+                            </div>
+                        </div>
                     </div>
-                </div>
-            </div>
-        </div>
-        
-        <div class="col-4 ">
-            <div class="card">
-                <div class="card-header">
-                    <h4>Irrigation and Weather</h4>
-                </div>
-                <div class="card-body">
-                    <div class="table-responsive table-editable">
-                        <span class="table-add float-right mb-3 mr-2"><a href="#!" class="text-success"><i class="fas fa-plus fa-2x" aria-hidden="true"></i></a></span>
-                        <table class="table table-striped table-hover">
-                            <thead class="table-warning">
-                            <tr>
-                              <th scope="col">#</th>
-                              <th scope="col">First</th>
-                              <th scope="col">Last</th>
-                              <th scope="col">Handle</th>
-                            </tr>
-                            </thead>
-                            <tbody>
-                            <tr>
-                              <th scope="row">1</th>
-                              <td>Mark</td>
-                              <td>Otto</td>
-                              <td>@mdo</td>
-                            </tr>
-                            <tr>
-                              <th scope="row">2</th>
-                              <td>Jacob</td>
-                              <td>Thornton</td>
-                              <td>@fat</td>
-                            </tr>
-                            <tr>
-                              <th scope="row">3</th>
-                              <td>Larry</td>
-                              <td>the Bird</td>
-                              <td>@twitter</td>
-                            </tr>
-                            </tbody>
-                        </table>
+                </div><!-- /crop information -->
+
+            </div><!-- /container-fluid -->
+
+        </main>
+
+        <!-- ── Create New Paddock modal ──────────────────────────────────────── -->
+        <div class="modal fade" id="createPaddock" tabindex="-1"
+             aria-labelledby="createPaddockLabel" aria-hidden="true">
+            <div class="modal-dialog modal-lg modal-dialog-centered">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <h5 class="modal-title" id="createPaddockLabel">Create Paddock Record</h5>
+                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                     </div>
-                </div>
-            </div>
-        </div>
-        
-        
-    </div>
-    
-</div>
-					</div>
-
-				</div>
-
-			</main>
-			
-			<footer class="py-4 bg-light mt-auto">
-                <div class="container-fluid px-4">
-                    <div class="d-flex align-items-center justify-content-between small">
-                        <div class="text-muted">[[SimpleCopyright? &startYear=`2003`]]. All Rights Reserved <a href="[[~1]]"></a></div>
-                        <div>
-                            <a href="[[~39~]]">Privacy Policy</a>
-                            &middot;
-                            <a href="[[~39~]]">Terms &amp; Conditions</a>
+                    <form method="post" action="/controllers/blockSubmit.php" id="createPaddockForm">
+                        <div class="modal-body">
+                            <input type="hidden" name="csrf_token"
+                                   value="<?= $h(generateCsrfToken()) ?>">
+                            <input type="hidden" name="action" value="create">
+
+                            <h6>Block Identification</h6>
+                            <div class="row mb-3">
+                                <div class="col">
+                                    <label class="form-label">Block ID</label>
+                                    <input type="text" class="form-control form-control-sm"
+                                           name="block_id" placeholder="e.g. BLK-001" required>
+                                </div>
+                                <div class="col">
+                                    <label class="form-label">Block Name</label>
+                                    <input type="text" class="form-control form-control-sm"
+                                           name="name" placeholder="e.g. North Paddock" required>
+                                </div>
+                            </div>
+
+                            <hr>
+                            <h6>Location / Sizing</h6>
+
+                            <div class="mb-3">
+                                <label class="form-label">Location / Address</label>
+                                <input type="text" class="form-control form-control-sm"
+                                       name="location" placeholder="Block address">
+                            </div>
+
+                            <div class="row mb-3">
+                                <div class="col">
+                                    <label class="form-label">Area (hectares)</label>
+                                    <input type="number" step="0.01" class="form-control form-control-sm"
+                                           id="create_area_ha" name="area_ha" placeholder="0.00"
+                                           oninput="areaConverter('area_ha',this.value,'create')">
+                                    <div class="form-text">in hectares</div>
+                                </div>
+                                <div class="col">
+                                    <label class="form-label">Area (acres)</label>
+                                    <input type="number" step="0.01" class="form-control form-control-sm"
+                                           id="create_area_ac" placeholder="0.00"
+                                           oninput="areaConverter('area_ac',this.value,'create')">
+                                    <div class="form-text">in acres</div>
+                                </div>
+                                <div class="col">
+                                    <label class="form-label">GPS Coordinates</label>
+                                    <input type="text" class="form-control form-control-sm"
+                                           name="gps" placeholder="e.g. -33.8688, 151.2093">
+                                </div>
+                            </div>
+
+                            <hr>
+                            <h6>Soil Classification</h6>
+                            <div class="row">
+                                <div class="col">
+                                    <label class="form-label">Soil Type</label>
+                                    <select class="form-select form-select-sm" name="analysis_type">
+                                        <option value="">Select soil type...</option>
+                                        <option value="sandy">Sandy</option>
+                                        <option value="light">Light</option>
+                                        <option value="medium">Medium</option>
+                                        <option value="heavy">Heavy</option>
+                                    </select>
+                                </div>
+                            </div>
+
+                        </div><!-- /modal-body -->
+                        <div class="modal-footer">
+                            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
+                            <button type="submit" class="btn btn-success">Create Paddock</button>
                         </div>
-                    </div>
+                    </form>
                 </div>
-            </footer>
-            
-		</div>
-
-	</div>
-
-	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
-	<script>
-    	/*!
-            * Start Bootstrap - SB Admin v7.0.3 (https://startbootstrap.com/template/sb-admin)
-            * Copyright 2013-2021 Start Bootstrap
-            * Licensed under MIT (https://github.com/StartBootstrap/startbootstrap-sb-admin/blob/master/LICENSE)
-            */
-            // 
-        // Scripts
-        // 
-        
-        window.addEventListener('DOMContentLoaded', event => {
-        
-            // Toggle the side navigation
-            const sidebarToggle = document.body.querySelector('#sidebarToggle');
-            if (sidebarToggle) {
-                // Uncomment Below to persist sidebar toggle between refreshes
-                // if (localStorage.getItem('sb|sidebar-toggle') === 'true') {
-                //     document.body.classList.toggle('sb-sidenav-toggled');
-                // }
-                sidebarToggle.addEventListener('click', event => {
-                    event.preventDefault();
-                    document.body.classList.toggle('sb-sidenav-toggled');
-                    localStorage.setItem('sb|sidebar-toggle', document.body.classList.contains('sb-sidenav-toggled'));
-                });
-            }
-        
-        });
-
-	</script>
-	<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js" crossorigin="anonymous"></script>
-	<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" crossorigin="anonymous"></script>
-</body>
-</html>
+            </div>
+        </div><!-- /createPaddock modal -->
+
+<?php include __DIR__ . '/../../layouts/footer.php'; ?>
+
+<script>
+/**
+ * Convert between hectares and acres in Create and Edit paddock modals.
+ * suffix: 'create' for the create modal, or the rowid for edit modals.
+ */
+function areaConverter(source, valNum, suffix) {
+    valNum = parseFloat(valNum) || 0;
+    var haId = (suffix === 'create') ? 'create_area_ha' : 'edit_area_ha_' + suffix;
+    var acId = (suffix === 'create') ? 'create_area_ac' : 'edit_area_ac_' + suffix;
+    var haEl = document.getElementById(haId);
+    var acEl = document.getElementById(acId);
+    if (!haEl || !acEl) return;
+
+    if (source === 'area_ha') {
+        acEl.value = (valNum / 0.404686).toFixed(2);
+    } else {
+        haEl.value = (valNum / 2.47105).toFixed(2);
+    }
+}
+</script>

+ 185 - 14
dashboard/dashboard.php

@@ -1,22 +1,193 @@
-<!--content-->
-<div class="content-top">
+<?php
+require_once __DIR__ . '/../config/database.php';
+require_once __DIR__ . '/../lib/auth.php';
 
-[[$test-widget]]
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
+}
 
-[[$client-widget]]
+requireLogin();
 
-</div><!--div class="content-top" -->
+$pageTitle = 'Dashboard';
+$siteName  = 'Crop Monitor';
 
-<div class="content-mid">
-    
-[[$weather-widget]]
+include __DIR__ . '/../layouts/header.php';
+include __DIR__ . '/../layouts/navbar.php';
+?>
 
-[[$calendar-widget]]
+<div id="layoutSidenav">
+    <div id="layoutSidenav_nav">
+        <?php include __DIR__ . '/../layouts/sidebar.php'; ?>
+    </div>
+    <div id="layoutSidenav_content">
+        <main>
+            <div class="container-fluid px-4">
 
-</div><!--div class="content-mid" -->    
+                <h1 class="mt-4"><?= htmlspecialchars($pageTitle, ENT_QUOTES, 'UTF-8') ?></h1>
+                <ol class="breadcrumb mb-4">
+                    <li class="breadcrumb-item active">Dashboard</li>
+                </ol>
 
-<div class="content-bottom">
+                <!-- ── Summary cards ──────────────────────────────────────── -->
+                <div class="row">
 
-</div><!--div class="content-mid" -->     
-    
-<div class="clearfix"> </div>
+                    <div class="col-xl-3 col-sm-6 mb-3">
+                        <div class="card text-white bg-primary o-hidden h-100">
+                            <div class="card-body">
+                                <div class="card-body-icon"><i class="fas fa-fw fa-comments"></i></div>
+                                <div class="mr-5">26 New Messages!</div>
+                            </div>
+                            <a class="card-footer text-white clearfix small z-1" href="/dashboard/inbox.php">
+                                <span class="float-start">View Details</span>
+                                <span class="float-end"><i class="fas fa-angle-right"></i></span>
+                            </a>
+                        </div>
+                    </div>
+
+                    <div class="col-xl-3 col-sm-6 mb-3">
+                        <div class="card text-white bg-warning o-hidden h-100">
+                            <div class="card-body">
+                                <div class="card-body-icon"><i class="fas fa-fw fa-list"></i></div>
+                                <div class="mr-5">11 New Tasks!</div>
+                            </div>
+                            <a class="card-footer text-white clearfix small z-1" href="#">
+                                <span class="float-start">View Details</span>
+                                <span class="float-end"><i class="fas fa-angle-right"></i></span>
+                            </a>
+                        </div>
+                    </div>
+
+                    <div class="col-xl-3 col-sm-6 mb-3">
+                        <div class="card text-white bg-success o-hidden h-100">
+                            <div class="card-body">
+                                <div class="card-body-icon"><i class="fas fa-fw fa-seedling"></i></div>
+                                <div class="mr-5">New Soil Tests</div>
+                            </div>
+                            <a class="card-footer text-white clearfix small z-1"
+                               href="/dashboard/crop-analysis/soil-test-data/soil-test-data.php">
+                                <span class="float-start">View Details</span>
+                                <span class="float-end"><i class="fas fa-angle-right"></i></span>
+                            </a>
+                        </div>
+                    </div>
+
+                    <div class="col-xl-3 col-sm-6 mb-3">
+                        <div class="card text-white bg-danger o-hidden h-100">
+                            <div class="card-body">
+                                <div class="card-body-icon"><i class="fas fa-fw fa-life-ring"></i></div>
+                                <div class="mr-5">13 New Tickets!</div>
+                            </div>
+                            <a class="card-footer text-white clearfix small z-1" href="#">
+                                <span class="float-start">View Details</span>
+                                <span class="float-end"><i class="fas fa-angle-right"></i></span>
+                            </a>
+                        </div>
+                    </div>
+
+                </div><!-- /row: summary cards -->
+
+                <!-- ── Recent Analysis heading ─────────────────────────────── -->
+                <div class="row mb-3">
+                    <div class="col-md-12">
+                        <h5>Recent Analysis</h5>
+                    </div>
+                </div>
+
+                <!-- ── Weather widget + Calendar ──────────────────────────── -->
+                <div class="row">
+
+                    <!-- Weather widget -->
+                    <div class="col-md-7">
+                        <div class="weather">
+                            <div class="weather-top">
+                                <div class="weather-top-left">
+                                    <div class="degree">
+                                        <figure class="icons">
+                                            <canvas id="partly-cloudy-day" width="64" height="64"></canvas>
+                                        </figure>
+                                        <span>37°</span>
+                                        <div class="clearfix"></div>
+                                    </div>
+                                    <p>
+                                        <?= date('l') ?>
+                                        <label><?= date('j') ?></label><sup><?= date('S') ?></sup>
+                                        <?= date('M') ?>
+                                    </p>
+                                </div>
+                                <div class="weather-top-right">
+                                    <p><i class="fa fa-map-marker"></i> &mdash;</p>
+                                    <label>&mdash;</label>
+                                </div>
+                                <div class="clearfix"></div>
+                            </div>
+
+                            <div class="weather-bottom">
+                                <?php
+                                $forecast = [
+                                    ['label' => 'Cloudy', 'icon' => 'cloudy',    'temp' => '20°', 'offset' => 1],
+                                    ['label' => 'Sunny',  'icon' => 'clear-day', 'temp' => '37°', 'offset' => 2],
+                                    ['label' => 'Rainy',  'icon' => 'sleet',     'temp' => '7°',  'offset' => 3],
+                                    ['label' => 'Windy',  'icon' => 'wind',      'temp' => '14°', 'offset' => 4],
+                                ];
+                                foreach ($forecast as $day): ?>
+                                <div class="weather-bottom1">
+                                    <div class="weather-head">
+                                        <h4><?= $day['label'] ?></h4>
+                                        <figure class="icons">
+                                            <canvas id="fc-<?= $day['icon'] ?>" width="58" height="58"></canvas>
+                                        </figure>
+                                        <h6><?= $day['temp'] ?></h6>
+                                        <div class="bottom-head">
+                                            <p><?= date('F j', strtotime('+' . $day['offset'] . ' day')) ?></p>
+                                            <p><?= date('l',   strtotime('+' . $day['offset'] . ' day')) ?></p>
+                                        </div>
+                                    </div>
+                                </div>
+                                <?php endforeach; ?>
+                                <div class="clearfix"></div>
+                            </div>
+                        </div>
+                    </div><!-- /col: weather -->
+
+                    <!-- Calendar widget -->
+                    <div class="col-md-5">
+                        <div class="cal1 cal_2">
+                            <div id="clndr"></div>
+                        </div>
+                        <link rel="stylesheet" href="/client-assets/css/clndr.css">
+                        <script src="/client-assets/js/underscore-min.js"></script>
+                        <script src="/client-assets/js/moment-2.2.1.js"></script>
+                        <script src="/client-assets/js/clndr.js"></script>
+                        <script src="/client-assets/js/site.js"></script>
+                    </div><!-- /col: calendar -->
+
+                </div><!-- /row: weather + calendar -->
+
+                <div class="content-bottom mt-4"></div>
+                <div class="clearfix"></div>
+
+            </div><!-- /container-fluid -->
+
+<?php include __DIR__ . '/../layouts/footer.php'; ?>
+
+<script>
+    // Initialise all Skycons in a single pass after DOM is ready
+    (function () {
+        var hero = new Skycons({ color: '#1ABC9C' });
+        hero.set('partly-cloudy-day', 'partly-cloudy-day');
+        hero.play();
+
+        var fc = new Skycons({ color: '#999' });
+        [
+            ['fc-cloudy',    'cloudy'],
+            ['fc-clear-day', 'clear-day'],
+            ['fc-sleet',     'sleet'],
+            ['fc-wind',      'wind'],
+        ].forEach(function (pair) {
+            if (document.getElementById(pair[0])) {
+                fc.set(pair[0], pair[1]);
+            }
+        });
+        fc.play();
+    })();
+</script>

+ 123 - 43
login/change-password.php

@@ -1,44 +1,124 @@
-<div class="modal" id="change-password" tabindex="-1" role="dialog">
-  <div class="modal-dialog" role="document">
-    <div class="modal-content">
-      <div class="modal-header">
-        <h5 class="modal-title">Change Password</h5>
-        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
-          <span aria-hidden="true">&times;</span>
-        </button>
-      </div>
-      <div class="modal-body">
-        <div class="updprof-error">[[!+cp.error_message]]</div>
-        [[!ChangePassword?
-            &submitVar=`change-password`
-            &placeholderPrefix=`cp.`
-            &validateOldPassword=`1`
-            &validate=`nospam:blank`
-            &successMessage=`Your password is changed`
-        ]]
-        
-        <form action="[[~[[*id]]]]" method="post">
-            <input type="hidden" name="nospam" value="" />
-          <div class="form-group">
-            <label for="password_old">Old Password <span style="color: red;">[[!+cp.error.password_old]]</span></label>
-            <input type="password" class="form-control" name="password_old" id="password_old" value="[[+cp.password_old]]" aria-describedby="password_old" placeholder="Old Password">
-            <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
-          </div>
-          <div class="form-group">
-            <label for="exampleInputPassword1">New Password <span style="color: red;">[[!+cp.error.password_new]]</span></label>
-            <input type="password" class="form-control" name="password_new" id="password_new" value="[[+cp.password_new]]" placeholder="New Password">
-          </div>
-          <div class="form-group">
-            <label for="exampleInputPassword1">Confirm New Password <span style="color: red;">[[!+cp.error.password_new_confirm]]</span></label>
-            <input type="password" class="form-control" name="password_new_confirm" id="password_new_confirm" value="[[+cp.password_new_confirm]]" placeholder="Confirm New Password">
-          </div>
-          <input type="submit" class="btn btn-primary" name="change-password" value="Change Password" >
-        </form>
-        
-      </div>
-      <div class="modal-footer">
-
-      </div>
+<?php
+require_once __DIR__ . '/../config/database.php';
+require_once __DIR__ . '/../lib/auth.php';
+require_once __DIR__ . '/../lib/csrf.php';
+
+if (session_status() === PHP_SESSION_NONE) {
+    session_start();
+}
+
+requireLogin();
+
+$pageTitle = 'Change Password';
+$siteName  = 'Crop Monitor';
+
+$errors  = [];
+$success = false;
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+    if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) {
+        $errors[] = 'Invalid security token. Please try again.';
+    } else {
+        $oldPassword = $_POST['password_old']         ?? '';
+        $newPassword = $_POST['password_new']         ?? '';
+        $confirm     = $_POST['password_new_confirm'] ?? '';
+
+        if ($oldPassword === '') {
+            $errors[] = 'Current password is required.';
+        }
+        if (strlen($newPassword) < 8) {
+            $errors[] = 'New password must be at least 8 characters.';
+        }
+        if ($newPassword !== $confirm) {
+            $errors[] = 'New passwords do not match.';
+        }
+
+        if (empty($errors)) {
+            if (changePassword(getCurrentUserId(), $oldPassword, $newPassword)) {
+                regenerateCsrfToken();
+                $success = true;
+            } else {
+                $errors[] = 'Current password is incorrect.';
+            }
+        }
+    }
+}
+
+include __DIR__ . '/../layouts/header.php';
+include __DIR__ . '/../layouts/navbar.php';
+?>
+
+<div id="layoutSidenav">
+    <div id="layoutSidenav_nav">
+        <?php include __DIR__ . '/../layouts/sidebar.php'; ?>
     </div>
-  </div>
-</div>
+    <div id="layoutSidenav_content">
+        <main>
+            <div class="container-fluid px-4">
+
+                <h1 class="mt-4"><?= htmlspecialchars($pageTitle, ENT_QUOTES, 'UTF-8') ?></h1>
+                <ol class="breadcrumb mb-4">
+                    <li class="breadcrumb-item"><a href="/dashboard/dashboard.php">Dashboard</a></li>
+                    <li class="breadcrumb-item active">Change Password</li>
+                </ol>
+
+                <div class="row justify-content-center">
+                    <div class="col-xl-6 col-lg-8">
+                        <div class="card shadow mb-4">
+                            <div class="card-header py-3">
+                                <h6 class="m-0 fw-bold text-success">Update Your Password</h6>
+                            </div>
+                            <div class="card-body">
+
+                                <?php if ($success): ?>
+                                    <div class="alert alert-success" role="alert">
+                                        <i class="fas fa-check-circle me-2"></i>Your password has been updated successfully.
+                                    </div>
+                                <?php endif; ?>
+
+                                <?php if (!empty($errors)): ?>
+                                    <div class="alert alert-danger" role="alert">
+                                        <ul class="mb-0">
+                                            <?php foreach ($errors as $e): ?>
+                                                <li><?= htmlspecialchars($e, ENT_QUOTES, 'UTF-8') ?></li>
+                                            <?php endforeach; ?>
+                                        </ul>
+                                    </div>
+                                <?php endif; ?>
+
+                                <form method="post" action="/login/change-password.php">
+                                    <input type="hidden" name="csrf_token"
+                                           value="<?= htmlspecialchars(generateCsrfToken(), ENT_QUOTES, 'UTF-8') ?>">
+
+                                    <div class="mb-3">
+                                        <label for="password_old" class="form-label">Current Password</label>
+                                        <input type="password" class="form-control" id="password_old"
+                                               name="password_old" placeholder="Current password" required>
+                                    </div>
+
+                                    <div class="mb-3">
+                                        <label for="password_new" class="form-label">New Password</label>
+                                        <input type="password" class="form-control" id="password_new"
+                                               name="password_new" placeholder="New password (min 8 characters)" required>
+                                    </div>
+
+                                    <div class="mb-3">
+                                        <label for="password_new_confirm" class="form-label">Confirm New Password</label>
+                                        <input type="password" class="form-control" id="password_new_confirm"
+                                               name="password_new_confirm" placeholder="Repeat new password" required>
+                                    </div>
+
+                                    <button type="submit" class="btn btn-success">
+                                        <i class="fas fa-key me-1"></i>Change Password
+                                    </button>
+                                    <a href="/dashboard/dashboard.php" class="btn btn-secondary ms-2">Cancel</a>
+                                </form>
+
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+            </div><!-- /container-fluid -->
+
+<?php include __DIR__ . '/../layouts/footer.php'; ?>