diff --git a/add_item.php b/add_item.php new file mode 100644 index 0000000..551fc0c --- /dev/null +++ b/add_item.php @@ -0,0 +1,250 @@ +prepare($sql); + + $stmt->execute([ + ':acquisition_date' => $_POST['acquisition_date'], + ':item_code' => $_POST['item_code'], + ':company_origin' => $_POST['company_origin'], + ':category' => $_POST['category'], + ':sub_category' => $_POST['sub_category'], + ':po_number' => $_POST['po_number'], + ':item_name' => $_POST['item_name'], + ':acquisition_price' => $_POST['acquisition_price'], + ':item_user_name' => $_POST['item_user_name'], + ':user_division' => $_POST['user_division'], + ':user_department' => $_POST['user_department'], + ':location_city' => $_POST['location_city'], + ':location_building' => $_POST['location_building'], + ':location_area' => $_POST['location_area'], + ':current_condition' => $_POST['current_condition'], + ':condition_at_acquisition' => $_POST['condition_at_acquisition'], + ':item_information' => $_POST['item_information'] ?? '', + ':asset_status' => $_POST['asset_status'], + ':transfer_status' => $_POST['transfer_status'] ?? 'N/A', + ]); + + $success_message = "Inventory item added successfully!"; + + } catch (Exception $e) { + $error_message = "Error: " . $e->getMessage(); + // Check for duplicate item_code + if ($e instanceof PDOException && $e->errorInfo[1] == 1062) { + $error_message = "Error: An item with this Item Code already exists."; + } + } +} + +// Static options for dropdowns +$categories = ['Electronics', 'Furniture', 'Software', 'Office Supplies']; +$conditions = ['Good', 'Minor Damage', 'Major Damage', 'Broken']; +$conditions_acq = ['New', 'Used', 'Refurbished']; +$asset_statuses = ['Active', 'In Use', 'In Storage', 'Transferred', 'Disposed']; +$transfer_statuses = ['Pending', 'Approved', 'Rejected', 'Completed', 'N/A']; +$divisions = ['IT', 'HR', 'Finance', 'Operations']; +$departments = ['Help Desk', 'Recruitment', 'Accounting', 'Logistics']; +$cities = ['New York', 'London', 'Tokyo', 'Sydney']; + +?> + + + + + + Add New Inventory Item + + + + +
+

Inventory Management System

+ +
+ +
+
+

Add a New Inventory Item

+

Fill out the form below to add a new asset to the inventory.

+ + +
+ + +
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+ + +
+ +
+ + +
+
+
+
+ + + + + diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..35ef6b1 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,283 @@ +/* General Body Styles */ +body { + font-family: 'Roboto', sans-serif; + background-color: #ECF0F1; + color: #333; + line-height: 1.6; + margin: 0; +} + +/* App Header */ +.app-header { + background: linear-gradient(135deg, #2A3F54 0%, #3E5771 100%); + color: #FFFFFF; + padding: 1rem 2rem; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.app-header h1 { + font-family: 'Roboto Slab', serif; + margin: 0; + font-size: 1.5rem; + color: #FFFFFF; +} + +.app-header nav a { + color: #FFFFFF; + text-decoration: none; + margin-left: 1.5rem; + font-weight: 500; + padding-bottom: 0.25rem; + border-bottom: 2px solid transparent; + transition: border-color 0.3s ease; +} + +.app-header nav a.active, +.app-header nav a:hover { + border-color: #2ECC71; +} + + +/* Main Container */ +.container { + max-width: 1200px; + margin: 2rem auto; + padding: 0 2rem; +} + +/* Card Style */ +.card { + background-color: #FFFFFF; + border-radius: 0.5rem; + box-shadow: 0 4px 6px rgba(0,0,0,0.05); + padding: 2rem; + margin-bottom: 2rem; +} + +/* Form Styles */ +.form-container h2 { + font-family: 'Roboto Slab', serif; + color: #2A3F54; + margin-top: 0; + margin-bottom: 0.5rem; +} + +.form-container p { + margin-top: 0; + margin-bottom: 2rem; + color: #555; +} + +.form-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 2rem; +} + +.form-column { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.form-group { + display: flex; + flex-direction: column; +} + +.form-group label { + font-weight: 700; + margin-bottom: 0.5rem; + color: #3E5771; +} + +.form-group input, +.form-group select, +.form-group textarea { + width: 100%; + padding: 0.75rem; + border: 1px solid #ccc; + border-radius: 0.25rem; + font-size: 1rem; + transition: border-color 0.3s ease, box-shadow 0.3s ease; +} + +.form-group input:focus, +.form-group select:focus, +.form-group textarea:focus { + outline: none; + border-color: #2A3F54; + box-shadow: 0 0 0 2px rgba(42, 63, 84, 0.2); +} + +.form-full-width { + grid-column: 1 / -1; +} + +.form-actions { + grid-column: 1 / -1; + display: flex; + justify-content: flex-end; + gap: 1rem; + margin-top: 2rem; +} + +/* Buttons */ +.btn { + padding: 0.75rem 1.5rem; + border-radius: 0.25rem; + text-decoration: none; + color: #fff; + font-weight: bold; + transition: background-color 0.3s ease, transform 0.2s ease; + border: none; + cursor: pointer; +} + +.btn:hover { + transform: translateY(-2px); +} + +.btn-primary { + background-color: #2ECC71; +} + +.btn-primary:hover { + background-color: #25a25a; +} + +.btn-secondary { + background-color: #95a5a6; +} + +.btn-secondary:hover { + background-color: #7f8c8d; +} + + +/* Toast Notifications */ +.toast { + padding: 1rem; + margin-bottom: 1.5rem; + border-radius: 0.25rem; + color: #fff; + font-weight: 500; +} + +.toast.success { + background-color: #2ECC71; +} + +.toast.error { + background-color: #E74C3C; +} + + +/* Inventory List Specific */ +.header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 2rem; + border-bottom: 1px solid #ddd; + padding-bottom: 1rem; +} + +.search-and-filter-section { + margin-bottom: 2rem; +} + +.search-bar input { + width: 100%; + padding: 0.75rem; + border: 1px solid #ccc; + border-radius: 0.25rem; + margin-bottom: 1rem; +} + +.filter-form { + margin-bottom: 2rem; +} + +.filter-controls { + display: flex; + gap: 1rem; + align-items: center; +} + +.filter-controls select { + padding: 0.75rem; + border: 1px solid #ccc; + border-radius: 0.25rem; + flex-grow: 1; +} + +.filter-controls .btn { + padding: 0.75rem 1.5rem; +} + +.inventory-table-container { + overflow-x: auto; +} + +.inventory-table { + width: 100%; + border-collapse: collapse; +} + +.inventory-table th, .inventory-table td { + padding: 1rem; + text-align: left; + border-bottom: 1px solid #ddd; +} + +.inventory-table th { + font-family: 'Roboto Slab', serif; +} + +.inventory-table th a { + text-decoration: none; + color: #2A3F54; +} + +.inventory-table tbody tr:hover { + background-color: #f9f9f9; +} + +.status { + padding: 0.25rem 0.5rem; + border-radius: 1rem; + color: #fff; + font-size: 0.8rem; + font-weight: bold; + text-transform: uppercase; +} + +.status-active, .status-in-use { + background-color: #2ECC71; +} + +.status-in-storage { + background-color: #3498DB; +} + +.status-transferred { + background-color: #F1C40F; +} + +.status-disposed { + background-color: #E74C3C; +} + +/* App Footer */ +.app-footer { + text-align: center; + padding: 2rem 0; + margin-top: 2rem; + color: #777; + font-size: 0.9rem; +} + diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..2d0d5a4 --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,36 @@ +document.addEventListener('DOMContentLoaded', function() { + const addItemForm = document.getElementById('add-item-form'); + + if (addItemForm) { + addItemForm.addEventListener('submit', function(e) { + const requiredInputs = addItemForm.querySelectorAll('[required]'); + let firstError = null; + + requiredInputs.forEach(input => { + if (!input.value.trim()) { + input.style.borderColor = '#E74C3C'; + if (!firstError) { + firstError = input; + } + } else { + input.style.borderColor = '#ccc'; + } + }); + + if (firstError) { + e.preventDefault(); + alert('Please fill out all required fields.'); + firstError.focus(); + } + }); + } + + // Auto-hide toast messages + const toastMessages = document.querySelectorAll('.toast'); + toastMessages.forEach(toast => { + setTimeout(() => { + toast.style.display = 'none'; + }, 5000); // Hide after 5 seconds + }); + +}); diff --git a/db/config.php b/db/config.php index 89075af..f6a06d2 100644 --- a/db/config.php +++ b/db/config.php @@ -1,17 +1,64 @@ PDO::ERRMODE_EXCEPTION, - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, - ]); - } - return $pdo; + $dsn = "mysql:host=$host;dbname=$db;charset=$charset"; + $options = [ + PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, + PDO::ATTR_EMULATE_PREPARES => false, + ]; + try { + $pdo = new PDO($dsn, $user, $pass, $options); + } catch (PDOException $e) { + throw new PDOException($e->getMessage(), (int)$e->getCode()); + } + return $pdo; } + +function create_schema($pdo) { + $queries = [ + 'CREATE TABLE IF NOT EXISTS `inventory_items` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `acquisition_date` DATE NOT NULL, + `item_code` VARCHAR(255) UNIQUE NOT NULL, + `company_origin` VARCHAR(255) NOT NULL, + `category` VARCHAR(255) NOT NULL, + `sub_category` VARCHAR(255) NOT NULL, + `po_number` VARCHAR(255) NOT NULL, + `item_name` VARCHAR(255) NOT NULL, + `acquisition_price` DECIMAL(10, 2) NOT NULL, + `item_user_name` VARCHAR(255) NOT NULL, + `user_division` VARCHAR(255) NOT NULL, + `user_department` VARCHAR(255) NOT NULL, + `location_city` VARCHAR(255) NOT NULL, + `location_building` VARCHAR(255) NOT NULL, + `location_area` VARCHAR(255) NOT NULL, + `current_condition` VARCHAR(255) NOT NULL, + `condition_at_acquisition` VARCHAR(255) NOT NULL, + `item_information` TEXT, + `asset_status` VARCHAR(255) NOT NULL, + `transfer_status` VARCHAR(255) NOT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP + );' + ]; + + foreach ($queries as $query) { + $pdo->exec($query); + } +} + +try { + $pdo = db_connect(); + create_schema($pdo); +} catch (PDOException $e) { + // In a real app, you'd log this error + error_log($e->getMessage()); + // You could also show a generic error page + // die("Database setup failed. Please check the logs."); +} +?> \ No newline at end of file diff --git a/index.php b/index.php index 7205f3d..0603f5e 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,23 @@ - - + - - - New Style - - - - - - - - - - - - - - - - - - - + + + Inventory Management System + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

+
+
+

Inventory Management System

+
+
+

Welcome!

+

You can start by viewing the inventory or adding a new item.

+ View Inventory + Add New Item +
-
- - + \ No newline at end of file diff --git a/inventory_list.php b/inventory_list.php new file mode 100644 index 0000000..a3162cf --- /dev/null +++ b/inventory_list.php @@ -0,0 +1,158 @@ +query("SELECT DISTINCT category FROM inventory_items ORDER BY category")->fetchAll(PDO::FETCH_COLUMN); +$statuses = $pdo->query("SELECT DISTINCT asset_status FROM inventory_items ORDER BY asset_status")->fetchAll(PDO::FETCH_COLUMN); +$locations = $pdo->query("SELECT DISTINCT location_city FROM inventory_items ORDER BY location_city")->fetchAll(PDO::FETCH_COLUMN); + +// Base query +$sql = "SELECT id, item_name, item_code, category, asset_status, location_city, acquisition_price, acquisition_date FROM inventory_items"; +$params = []; +$where_clauses = []; + +// Search +$search = $_GET['search'] ?? ''; +if ($search) { + $search_term = "%{$search}%"; + $where_clauses[] = "(item_name LIKE :search OR item_code LIKE :search OR po_number LIKE :search OR item_user_name LIKE :search OR user_department LIKE :search OR location_city LIKE :search OR company_origin LIKE :search)"; + $params[':search'] = $search_term; +} + +// Filters +$filter_category = $_GET['category'] ?? ''; +if ($filter_category) { + $where_clauses[] = "category = :category"; + $params[':category'] = $filter_category; +} + +$filter_status = $_GET['status'] ?? ''; +if ($filter_status) { + $where_clauses[] = "asset_status = :status"; + $params[':status'] = $filter_status; +} + +$filter_location = $_GET['location'] ?? ''; +if ($filter_location) { + $where_clauses[] = "location_city = :location"; + $params[':location'] = $filter_location; +} + +if (!empty($where_clauses)) { + $sql .= " WHERE " . implode(' AND ', $where_clauses); +} + +// Sorting +$sort_columns = ['item_name', 'item_code', 'category', 'asset_status', 'location_city', 'acquisition_price', 'acquisition_date']; +$sort_column = $_GET['sort'] ?? 'acquisition_date'; +$sort_direction = $_GET['dir'] ?? 'desc'; + +if (!in_array($sort_column, $sort_columns)) { + $sort_column = 'acquisition_date'; +} + +$sort_direction = strtolower($sort_direction) === 'asc' ? 'asc' : 'desc'; + +$sql .= " ORDER BY `$sort_column` $sort_direction"; + +$stmt = $pdo->prepare($sql); +$stmt->execute($params); +$items = $stmt->fetchAll(); + +function get_sort_link($column, $current_sort, $current_dir) { + $dir = ($current_sort === $column && $current_dir === 'asc') ? 'desc' : 'asc'; + $query_params = http_build_query(array_merge($_GET, ['sort' => $column, 'dir' => $dir])); + return '?' . $query_params; +} + +?> + + + + + + Inventory List + + + + +
+
+

Inventory List

+ Add New Item +
+ +
+
+ +
+ + + + + Reset +
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Item NameItem CodeCategoryStatusLocationPriceAcquisition DateActions
No inventory items found matching your criteria.
$ + Edit +
+
+
+ + + \ No newline at end of file