Initial Commit with ENVs, directory structures, cursor rules, etc
This commit is contained in:
commit
1a65e69d25
22
.cursor/rules/naming-conventions.mdc
Normal file
22
.cursor/rules/naming-conventions.mdc
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
description:
|
||||||
|
globs: *.php,*.js,*.css
|
||||||
|
alwaysApply: false
|
||||||
|
---
|
||||||
|
.php files should use the following naming conventions:
|
||||||
|
"classes": "PascalCase",
|
||||||
|
"functions": "camelCase",
|
||||||
|
"variables": "camelCase",
|
||||||
|
"constants": "UPPER_SNAKE_CASE"
|
||||||
|
|
||||||
|
.js files should use the following naming conventions:
|
||||||
|
"functions": "camelCase",
|
||||||
|
"variables": "camelCase",
|
||||||
|
"constants": "UPPER_SNAKE_CASE"
|
||||||
|
|
||||||
|
|
||||||
|
.css files should us the following naming conventions:
|
||||||
|
|
||||||
|
"ids": "camelCase",
|
||||||
|
|
||||||
|
"classes": "kebab-case"
|
||||||
8
.cursor/rules/project-guidelines.mdc
Normal file
8
.cursor/rules/project-guidelines.mdc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
description:
|
||||||
|
globs:
|
||||||
|
alwaysApply: true
|
||||||
|
---
|
||||||
|
This is a zero build project. We are not allowing packages to be installed or suggested for this project. No dependendcies on the backend/server side. On the front-end we will only allow CDN js and css files or libraries.
|
||||||
|
|
||||||
|
The following are allowed on the front-end: bootstrap|fontawesome|jquery
|
||||||
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Data directory
|
||||||
|
/data/
|
||||||
|
/data/*.json
|
||||||
|
|
||||||
|
# Exports directory
|
||||||
|
/exports/
|
||||||
|
/exports/*.json
|
||||||
|
/exports/export_log.txt
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.sublime-*
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
15
.htaccess
Normal file
15
.htaccess
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Protect data directory
|
||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteRule ^data/.* - [F,L]
|
||||||
|
RewriteRule ^exports/.* - [F,L]
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
# Disable directory browsing
|
||||||
|
Options -Indexes
|
||||||
|
|
||||||
|
# Deny access to hidden files and directories
|
||||||
|
<FilesMatch "^\.">
|
||||||
|
Order allow,deny
|
||||||
|
Deny from all
|
||||||
|
</FilesMatch>
|
||||||
59
assets/css/style.css
Normal file
59
assets/css/style.css
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/* Main Styles */
|
||||||
|
:root {
|
||||||
|
--primary-color: #4a90e2;
|
||||||
|
--secondary-color: #f5f5f5;
|
||||||
|
--text-color: #333;
|
||||||
|
--border-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab Styles */
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
padding: 10px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-bottom: none;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab.active {
|
||||||
|
background: white;
|
||||||
|
border-color: var(--border-color);
|
||||||
|
border-bottom: 1px solid white;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile Responsive */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
assets/js/main.js
Normal file
25
assets/js/main.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Tab functionality
|
||||||
|
const tabs = document.querySelectorAll('.tab');
|
||||||
|
const tabContents = document.querySelectorAll('.tab-content');
|
||||||
|
|
||||||
|
tabs.forEach(tab => {
|
||||||
|
tab.addEventListener('click', () => {
|
||||||
|
// Remove active class from all tabs
|
||||||
|
tabs.forEach(t => t.classList.remove('active'));
|
||||||
|
tabContents.forEach(content => content.style.display = 'none');
|
||||||
|
|
||||||
|
// Add active class to clicked tab
|
||||||
|
tab.classList.add('active');
|
||||||
|
|
||||||
|
// Show corresponding content
|
||||||
|
const targetId = tab.getAttribute('data-target');
|
||||||
|
document.getElementById(targetId).style.display = 'block';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize first tab as active
|
||||||
|
if (tabs.length > 0) {
|
||||||
|
tabs[0].click();
|
||||||
|
}
|
||||||
|
});
|
||||||
41
config/config.php
Normal file
41
config/config.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/env.php';
|
||||||
|
|
||||||
|
// Load environment variables
|
||||||
|
Env::load();
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
define('ROOT_PATH', dirname(__DIR__));
|
||||||
|
define('DATA_PATH', ROOT_PATH . '/data');
|
||||||
|
define('EXPORT_PATH', ROOT_PATH . '/exports');
|
||||||
|
|
||||||
|
// Google API Configuration
|
||||||
|
define('GOOGLE_CLIENT_ID', Env::get('GOOGLE_CLIENT_ID'));
|
||||||
|
define('GOOGLE_CLIENT_SECRET', Env::get('GOOGLE_CLIENT_SECRET'));
|
||||||
|
define('GOOGLE_REDIRECT_URI', Env::get('GOOGLE_REDIRECT_URI'));
|
||||||
|
define('GOOGLE_CALENDAR_ID', Env::get('GOOGLE_CALENDAR_ID'));
|
||||||
|
define('GOOGLE_CALENDAR_EMBED_CODE', Env::get('GOOGLE_CALENDAR_EMBED_CODE'));
|
||||||
|
define('GOOGLE_DRIVE_FOLDER_ID', Env::get('GOOGLE_DRIVE_FOLDER_ID'));
|
||||||
|
|
||||||
|
// Application Settings
|
||||||
|
define('APP_ENV', Env::get('APP_ENV', 'production'));
|
||||||
|
define('APP_DEBUG', Env::get('APP_DEBUG', 'false') === 'true');
|
||||||
|
define('APP_URL', Env::get('APP_URL', 'http://localhost/family-hub'));
|
||||||
|
|
||||||
|
// Export settings
|
||||||
|
define('EXPORT_DESTINATION', EXPORT_PATH);
|
||||||
|
define('EXPORT_FREQUENCY', Env::get('EXPORT_FREQUENCY', 'daily'));
|
||||||
|
define('EXPORT_RETENTION_DAYS', (int)Env::get('EXPORT_RETENTION_DAYS', 30));
|
||||||
|
|
||||||
|
// Tab configuration
|
||||||
|
$TABS = [
|
||||||
|
'chores' => ['title' => 'Chores', 'icon' => 'tasks'],
|
||||||
|
'groceries' => ['title' => 'Grocery List', 'icon' => 'shopping-cart'],
|
||||||
|
'meals' => ['title' => 'Meal Plan', 'icon' => 'utensils']
|
||||||
|
];
|
||||||
|
|
||||||
|
// Load local configuration if exists
|
||||||
|
if (file_exists(__DIR__ . '/local.php')) {
|
||||||
|
include __DIR__ . '/local.php';
|
||||||
|
}
|
||||||
|
?>
|
||||||
41
config/env.php
Normal file
41
config/env.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Env {
|
||||||
|
private static $variables = [];
|
||||||
|
|
||||||
|
public static function load() {
|
||||||
|
$envFile = dirname(__DIR__) . '/.env';
|
||||||
|
|
||||||
|
if (!file_exists($envFile)) {
|
||||||
|
throw new Exception('.env file not found. Please create one based on .env.example');
|
||||||
|
}
|
||||||
|
|
||||||
|
$lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
// Skip comments
|
||||||
|
if (strpos(trim($line), '#') === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($name, $value) = explode('=', $line, 2);
|
||||||
|
$name = trim($name);
|
||||||
|
$value = trim($value);
|
||||||
|
|
||||||
|
// Remove quotes if present
|
||||||
|
if (strpos($value, '"') === 0 || strpos($value, "'") === 0) {
|
||||||
|
$value = substr($value, 1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$variables[$name] = $value;
|
||||||
|
putenv("$name=$value");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get($key, $default = null) {
|
||||||
|
return self::$variables[$key] ?? $default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function all() {
|
||||||
|
return self::$variables;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
env.example
Normal file
20
env.example
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Google API Credentials
|
||||||
|
GOOGLE_CLIENT_ID=your_client_id_here
|
||||||
|
GOOGLE_CLIENT_SECRET=your_client_secret_here
|
||||||
|
GOOGLE_REDIRECT_URI=http://localhost/family-hub/auth/google/callback
|
||||||
|
|
||||||
|
# Google Calendar
|
||||||
|
GOOGLE_CALENDAR_ID=your_calendar_id_here
|
||||||
|
GOOGLE_CALENDAR_EMBED_CODE=your_embed_code_here
|
||||||
|
|
||||||
|
# Google Drive
|
||||||
|
GOOGLE_DRIVE_FOLDER_ID=your_folder_id_here
|
||||||
|
|
||||||
|
# Application Settings
|
||||||
|
APP_ENV=development
|
||||||
|
APP_DEBUG=true
|
||||||
|
APP_URL=http://localhost/family-hub
|
||||||
|
|
||||||
|
# Export Settings
|
||||||
|
EXPORT_FREQUENCY=daily
|
||||||
|
EXPORT_RETENTION_DAYS=30
|
||||||
29
export.php
Normal file
29
export.php
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/includes/db.php';
|
||||||
|
require_once __DIR__ . '/includes/utils.php';
|
||||||
|
require_once __DIR__ . '/config/config.php';
|
||||||
|
|
||||||
|
function exportData($type) {
|
||||||
|
ensureExportDirectory();
|
||||||
|
$data = readJsonFile($type . '.json');
|
||||||
|
$filename = generateExportFilename($type);
|
||||||
|
$exportPath = EXPORT_DESTINATION . '/' . $filename;
|
||||||
|
|
||||||
|
return file_put_contents($exportPath, json_encode($data, JSON_PRETTY_PRINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle export request
|
||||||
|
if (isset($_GET['type'])) {
|
||||||
|
$type = sanitizeInput($_GET['type']);
|
||||||
|
if (in_array($type, ['chores', 'groceries', 'meals'])) {
|
||||||
|
if (exportData($type)) {
|
||||||
|
echo json_encode(['success' => true, 'message' => 'Export successful']);
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Export failed']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'Invalid export type']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echo json_encode(['success' => false, 'message' => 'No export type specified']);
|
||||||
|
}
|
||||||
29
gitignore
Normal file
29
gitignore
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Data files (contain user data)
|
||||||
|
/data/*.json
|
||||||
|
|
||||||
|
# Export directory
|
||||||
|
/exports/
|
||||||
|
|
||||||
|
# Environment-specific configurations
|
||||||
|
/config/local.php
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Editor files
|
||||||
|
.vscode/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
*.tmp
|
||||||
|
*.tmp.*
|
||||||
|
*.tmp/*
|
||||||
|
*.tmp/*.*
|
||||||
|
|
||||||
|
# Cache files
|
||||||
|
*.cache
|
||||||
|
*.cache.*
|
||||||
|
*.cache/*
|
||||||
|
*.cache/*.*
|
||||||
23
includes/db.php
Normal file
23
includes/db.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function readJsonFile($filename) {
|
||||||
|
$filepath = __DIR__ . '/../data/' . $filename;
|
||||||
|
if (!file_exists($filepath)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$content = file_get_contents($filepath);
|
||||||
|
return json_decode($content, true) ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeJsonFile($filename, $data) {
|
||||||
|
$filepath = __DIR__ . '/../data/' . $filename;
|
||||||
|
$json = json_encode($data, JSON_PRETTY_PRINT);
|
||||||
|
return file_put_contents($filepath, $json);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureDataDirectory() {
|
||||||
|
$dataDir = __DIR__ . '/../data';
|
||||||
|
if (!file_exists($dataDir)) {
|
||||||
|
mkdir($dataDir, 0755, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
includes/footer.php
Normal file
17
includes/footer.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
</main>
|
||||||
|
<footer class="bg-light p-3 mt-4">
|
||||||
|
<div class="container text-center">
|
||||||
|
<p>Family Hub © <?= date('Y') ?></p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<!-- Bootstrap JS from CDN -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
|
<!-- jQuery from CDN (if needed) -->
|
||||||
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
|
|
||||||
|
<!-- Custom JavaScript -->
|
||||||
|
<script src="assets/js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
includes/header.php
Normal file
23
includes/header.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Family Hub</title>
|
||||||
|
|
||||||
|
<!-- Bootstrap CSS from CDN -->
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!-- Font Awesome icons from CDN -->
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
|
||||||
|
<!-- Custom styles -->
|
||||||
|
<link rel="stylesheet" href="assets/css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header class="bg-primary text-white p-3">
|
||||||
|
<div class="container">
|
||||||
|
<h1>Family Hub</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<main class="container py-4">
|
||||||
23
includes/utils.php
Normal file
23
includes/utils.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../config/config.php';
|
||||||
|
|
||||||
|
function sanitizeInput($input) {
|
||||||
|
if (is_array($input)) {
|
||||||
|
return array_map('sanitizeInput', $input);
|
||||||
|
}
|
||||||
|
return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate($date) {
|
||||||
|
return date('Y-m-d', strtotime($date));
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateExportFilename($type) {
|
||||||
|
return $type . '_' . date('Y-m-d') . '.json';
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureExportDirectory() {
|
||||||
|
if (!file_exists(EXPORT_DESTINATION)) {
|
||||||
|
mkdir(EXPORT_DESTINATION, 0755, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
index.php
Normal file
27
index.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
require_once 'config/config.php';
|
||||||
|
require_once 'includes/db.php';
|
||||||
|
require_once 'includes/utils.php';
|
||||||
|
|
||||||
|
// Determine which tab is active
|
||||||
|
$activeTab = isset($_GET['tab']) ? $_GET['tab'] : 'chores';
|
||||||
|
|
||||||
|
// Include header
|
||||||
|
include 'includes/header.php';
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="tabs">
|
||||||
|
<?php foreach ($TABS as $tabId => $tab): ?>
|
||||||
|
<a href="?tab=<?= $tabId ?>" class="tab <?= $activeTab === $tabId ? 'active' : '' ?>">
|
||||||
|
<i class="fa fa-<?= $tab['icon'] ?>"></i> <?= $tab['title'] ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
<?php include "tabs/$activeTab.php"; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php include 'includes/footer.php'; ?>
|
||||||
47
readme.md
Normal file
47
readme.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# Family Hub
|
||||||
|
|
||||||
|
A centralized family organization system with tabs for chores, grocery lists, and meal planning.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- Tabbed interface for different family needs
|
||||||
|
- JSON-based data storage
|
||||||
|
- Daily automated exports
|
||||||
|
- Mobile-friendly interface
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
1. Clone this repository to your web server
|
||||||
|
2. Ensure proper permissions on data directory
|
||||||
|
3. Set up the daily cron job for exports
|
||||||
|
4. Access the hub at http://your-local-ip/familyHub/
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
familyHub/
|
||||||
|
├── assets/ # Static assets
|
||||||
|
│ ├── css/ # CSS files
|
||||||
|
│ │ └── style.css
|
||||||
|
│ ├── js/ # JavaScript files
|
||||||
|
│ │ └── main.js
|
||||||
|
│ └── img/ # Images
|
||||||
|
├── config/ # Configuration files
|
||||||
|
│ └── config.php
|
||||||
|
├── data/ # JSON data storage (not tracked in git)
|
||||||
|
│ ├── chores.json
|
||||||
|
│ ├── groceries.json
|
||||||
|
│ └── meals.json
|
||||||
|
├── includes/ # PHP includes/components
|
||||||
|
│ ├── header.php
|
||||||
|
│ ├── footer.php
|
||||||
|
│ ├── db.php # JSON file handling functions
|
||||||
|
│ └── utils.php # Utility functions
|
||||||
|
├── exports/ # Temporary location for exports (not tracked in git)
|
||||||
|
├── scripts/ # Scripts for cron jobs
|
||||||
|
│ └── daily_export.php
|
||||||
|
├── tabs/ # Tab-specific functionality
|
||||||
|
│ ├── chores.php
|
||||||
|
│ ├── groceries.php
|
||||||
|
│ └── meals.php
|
||||||
|
├── .gitignore
|
||||||
|
├── .cursor.json # Cursor editor configuration
|
||||||
|
├── README.md
|
||||||
|
├── index.php # Main entry point
|
||||||
|
└── export.php # Export functionality
|
||||||
26
scripts/daily_export.php
Normal file
26
scripts/daily_export.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../includes/db.php';
|
||||||
|
require_once __DIR__ . '/../includes/utils.php';
|
||||||
|
require_once __DIR__ . '/../config/config.php';
|
||||||
|
|
||||||
|
// Export all data types
|
||||||
|
$types = ['chores', 'groceries', 'meals'];
|
||||||
|
$results = [];
|
||||||
|
|
||||||
|
foreach ($types as $type) {
|
||||||
|
$data = readJsonFile($type . '.json');
|
||||||
|
$filename = generateExportFilename($type);
|
||||||
|
$exportPath = EXPORT_DESTINATION . '/' . $filename;
|
||||||
|
|
||||||
|
if (file_put_contents($exportPath, json_encode($data, JSON_PRETTY_PRINT))) {
|
||||||
|
$results[$type] = 'success';
|
||||||
|
} else {
|
||||||
|
$results[$type] = 'failed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log results
|
||||||
|
$logFile = EXPORT_DESTINATION . '/export_log.txt';
|
||||||
|
$timestamp = date('Y-m-d H:i:s');
|
||||||
|
$logMessage = "[$timestamp] Export results: " . json_encode($results) . "\n";
|
||||||
|
file_put_contents($logFile, $logMessage, FILE_APPEND);
|
||||||
25
tabs/chores.php
Normal file
25
tabs/chores.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../includes/db.php';
|
||||||
|
require_once __DIR__ . '/../includes/utils.php';
|
||||||
|
|
||||||
|
$chores = readJsonFile('chores.json');
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="chores" class="tab-content">
|
||||||
|
<h2>Chores</h2>
|
||||||
|
<div class="chores-list">
|
||||||
|
<?php if (empty($chores)): ?>
|
||||||
|
<p>No chores added yet.</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<ul>
|
||||||
|
<?php foreach ($chores as $chore): ?>
|
||||||
|
<li>
|
||||||
|
<span class="chore-name"><?php echo sanitizeInput($chore['name']); ?></span>
|
||||||
|
<span class="chore-assignee"><?php echo sanitizeInput($chore['assignee']); ?></span>
|
||||||
|
<span class="chore-due-date"><?php echo formatDate($chore['due_date']); ?></span>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
25
tabs/groceries.php
Normal file
25
tabs/groceries.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../includes/db.php';
|
||||||
|
require_once __DIR__ . '/../includes/utils.php';
|
||||||
|
|
||||||
|
$groceries = readJsonFile('groceries.json');
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="groceries" class="tab-content">
|
||||||
|
<h2>Grocery List</h2>
|
||||||
|
<div class="groceries-list">
|
||||||
|
<?php if (empty($groceries)): ?>
|
||||||
|
<p>No items in the grocery list yet.</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<ul>
|
||||||
|
<?php foreach ($groceries as $item): ?>
|
||||||
|
<li>
|
||||||
|
<span class="item-name"><?php echo sanitizeInput($item['name']); ?></span>
|
||||||
|
<span class="item-quantity"><?php echo sanitizeInput($item['quantity']); ?></span>
|
||||||
|
<span class="item-category"><?php echo sanitizeInput($item['category']); ?></span>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
25
tabs/meals.php
Normal file
25
tabs/meals.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../includes/db.php';
|
||||||
|
require_once __DIR__ . '/../includes/utils.php';
|
||||||
|
|
||||||
|
$meals = readJsonFile('meals.json');
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="meals" class="tab-content">
|
||||||
|
<h2>Meal Planning</h2>
|
||||||
|
<div class="meals-list">
|
||||||
|
<?php if (empty($meals)): ?>
|
||||||
|
<p>No meals planned yet.</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<ul>
|
||||||
|
<?php foreach ($meals as $meal): ?>
|
||||||
|
<li>
|
||||||
|
<span class="meal-name"><?php echo sanitizeInput($meal['name']); ?></span>
|
||||||
|
<span class="meal-date"><?php echo formatDate($meal['date']); ?></span>
|
||||||
|
<span class="meal-type"><?php echo sanitizeInput($meal['type']); ?></span>
|
||||||
|
</li>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Loading…
x
Reference in New Issue
Block a user