Initialv1
This commit is contained in:
parent
3399f0248f
commit
3be446013d
80
assets/css/custom.css
Normal file
80
assets/css/custom.css
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
@import url('https://fonts.googleapis.com/css2?family=Georgia&display=swap');
|
||||
|
||||
body {
|
||||
background-color: #F8FAFC;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
color: #1F2937;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Georgia', serif;
|
||||
}
|
||||
|
||||
.theme-card {
|
||||
border-radius: 12px;
|
||||
border: 1px solid #E5E7EB;
|
||||
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.theme-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.theme-card .card-body {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #6366F1;
|
||||
border-color: #6366F1;
|
||||
border-radius: 9999px;
|
||||
padding: 0.75rem 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #4F46E5;
|
||||
border-color: #4F46E5;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: #EC4899;
|
||||
border-color: #EC4899;
|
||||
border-radius: 9999px;
|
||||
padding: 0.75rem 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: #DB2777;
|
||||
border-color: #DB2777;
|
||||
}
|
||||
|
||||
.ritual-step {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ritual-step.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.progress-bar-container {
|
||||
height: 4px;
|
||||
background-color: #E5E7EB;
|
||||
border-radius: 9999px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar-fill {
|
||||
height: 100%;
|
||||
background-color: #6366F1;
|
||||
width: 0%;
|
||||
transition: width 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.timer {
|
||||
font-size: 3rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
91
assets/js/main.js
Normal file
91
assets/js/main.js
Normal file
@ -0,0 +1,91 @@
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const ritualSteps = document.querySelectorAll('.ritual-step');
|
||||
const nextButtons = document.querySelectorAll('.next-step');
|
||||
const progressBar = document.querySelector('.progress-bar-fill');
|
||||
const timerElement = document.getElementById('timer');
|
||||
const beginButton = document.getElementById('begin-ritual');
|
||||
|
||||
let currentStep = 0;
|
||||
let timerInterval;
|
||||
|
||||
function showStep(stepIndex) {
|
||||
ritualSteps.forEach((step, index) => {
|
||||
step.classList.toggle('active', index === stepIndex);
|
||||
});
|
||||
const progress = ((stepIndex) / (ritualSteps.length - 2)) * 100;
|
||||
if(progressBar) {
|
||||
progressBar.style.width = `${progress}%`;
|
||||
}
|
||||
}
|
||||
|
||||
function startTimer(duration) {
|
||||
let timer = duration, minutes, seconds;
|
||||
if(!timerElement) return;
|
||||
|
||||
const updateTimer = () => {
|
||||
minutes = parseInt(timer / 60, 10);
|
||||
seconds = parseInt(timer % 60, 10);
|
||||
|
||||
minutes = minutes < 10 ? "0" + minutes : minutes;
|
||||
seconds = seconds < 10 ? "0" + seconds : seconds;
|
||||
|
||||
timerElement.textContent = minutes + ":" + seconds;
|
||||
|
||||
if (--timer < 0) {
|
||||
clearInterval(timerInterval);
|
||||
// Optionally, move to next step automatically
|
||||
if(currentStep < ritualSteps.length - 1) {
|
||||
currentStep++;
|
||||
showStep(currentStep);
|
||||
} else {
|
||||
// Handle completion
|
||||
}
|
||||
}
|
||||
};
|
||||
updateTimer();
|
||||
timerInterval = setInterval(updateTimer, 1000);
|
||||
}
|
||||
|
||||
if(beginButton) {
|
||||
beginButton.addEventListener('click', () => {
|
||||
currentStep = 1; // Move to the first ritual step
|
||||
showStep(currentStep);
|
||||
startTimer(90); // 90 second timer
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
nextButtons.forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
if (currentStep < ritualSteps.length - 1) {
|
||||
currentStep++;
|
||||
showStep(currentStep);
|
||||
|
||||
// If this is the last step, log progress
|
||||
if (currentStep === ritualSteps.length - 1) {
|
||||
const theme = new URLSearchParams(window.location.search).get('theme') || 'gratitude';
|
||||
fetch('log_progress.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ theme: theme })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (!data.success) {
|
||||
console.error('Failed to log progress.');
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error logging progress:', error));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Initial setup
|
||||
if(ritualSteps.length > 0) {
|
||||
showStep(0);
|
||||
}
|
||||
});
|
||||
79
checkout.php
Normal file
79
checkout.php
Normal file
@ -0,0 +1,79 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Ensure user is logged in
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Include the Stripe PHP library (assuming it's installed via Composer)
|
||||
// require_once 'vendor/autoload.php';
|
||||
|
||||
// Set your Stripe API key
|
||||
// \Stripe\Stripe::setApiKey('YOUR_STRIPE_SECRET_KEY');
|
||||
|
||||
$plan = $_GET['plan'] ?? 'basic';
|
||||
|
||||
$line_items = [];
|
||||
|
||||
if ($plan === 'basic') {
|
||||
$line_items[] = [
|
||||
'price_data' => [
|
||||
'currency' => 'usd',
|
||||
'product_data' => [
|
||||
'name' => 'Basic Plan',
|
||||
],
|
||||
'unit_amount' => 500, // $5.00
|
||||
'recurring' => [
|
||||
'interval' => 'month',
|
||||
],
|
||||
],
|
||||
'quantity' => 1,
|
||||
];
|
||||
} elseif ($plan === 'pro') {
|
||||
$line_items[] = [
|
||||
'price_data' => [
|
||||
'currency' => 'usd',
|
||||
'product_data' => [
|
||||
'name' => 'Pro Plan',
|
||||
],
|
||||
'unit_amount' => 1500, // $15.00
|
||||
'recurring' => [
|
||||
'interval' => 'month',
|
||||
],
|
||||
],
|
||||
'quantity' => 1,
|
||||
];
|
||||
} else {
|
||||
// Redirect to pricing page if plan is not recognized
|
||||
header('Location: pricing.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
/*
|
||||
try {
|
||||
$checkout_session = \Stripe\Checkout\Session::create([
|
||||
'payment_method_types' => ['card'],
|
||||
'line_items' => $line_items,
|
||||
'mode' => 'subscription',
|
||||
'success_url' => 'http://' . $_SERVER['HTTP_HOST'] . '/ritual.php',
|
||||
'cancel_url' => 'http://' . $_SERVER['HTTP_HOST'] . '/pricing.php',
|
||||
'customer_email' => $_SESSION['user_email'], // Pre-fill email
|
||||
'client_reference_id' => $_SESSION['user_id'],
|
||||
]);
|
||||
|
||||
header("Location: " . $checkout_session->url);
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
// Handle any errors that occur
|
||||
error_log('Stripe Error: ' . $e->getMessage());
|
||||
header('Location: pricing.php?error=1');
|
||||
exit;
|
||||
}
|
||||
*/
|
||||
|
||||
// For now, we will simulate a successful payment and redirect to the ritual page.
|
||||
header('Location: ritual.php?payment=success');
|
||||
exit;
|
||||
?>
|
||||
41
db/setup.php
Normal file
41
db/setup.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
// Create affirmations table
|
||||
$pdo->exec("CREATE TABLE IF NOT EXISTS affirmations (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
theme VARCHAR(255) NOT NULL,
|
||||
level VARCHAR(50) NOT NULL DEFAULT 'beginner',
|
||||
affirmation_text TEXT NOT NULL
|
||||
)");
|
||||
|
||||
// Clear existing affirmations to avoid duplicates on re-run
|
||||
$pdo->exec("TRUNCATE TABLE affirmations");
|
||||
|
||||
$affirmations = [
|
||||
'gratitude' => 'I am grateful for the abundance in my life.',
|
||||
'letting-go' => 'I release what no longer serves me.',
|
||||
'self-love' => 'I love and accept myself unconditionally.',
|
||||
'forgiveness' => 'I forgive myself and others, freeing myself from the past.',
|
||||
'abundance' => 'I am a magnet for success and good fortune.',
|
||||
'clarity' => 'My mind is clear and my path is unfolding perfectly.',
|
||||
'healing' => 'I am healing, whole, and strong.',
|
||||
'resilience' => 'I bounce back from challenges with ease.',
|
||||
'joy' => 'I choose joy and find it in every moment.',
|
||||
'peace' => 'I cultivate peace within and around me.'
|
||||
];
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO affirmations (theme, affirmation_text) VALUES (:theme, :affirmation_text)");
|
||||
|
||||
foreach ($affirmations as $theme => $text) {
|
||||
$stmt->execute(['theme' => $theme, 'affirmation_text' => $text]);
|
||||
}
|
||||
|
||||
echo "Database setup complete. 'affirmations' table created and seeded." . PHP_EOL;
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("Database setup failed: " . $e->getMessage());
|
||||
}
|
||||
19
db/setup_progress.php
Normal file
19
db/setup_progress.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS progress (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
user_id INT NOT NULL,
|
||||
theme VARCHAR(255) NOT NULL,
|
||||
completion_date DATE NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||
);
|
||||
";
|
||||
$pdo->exec($sql);
|
||||
echo "Progress table created successfully.";
|
||||
} catch (PDOException $e) {
|
||||
die("Could not connect to the database $dbname :" . $e->getMessage());
|
||||
}
|
||||
23
db/setup_subscriptions.php
Normal file
23
db/setup_subscriptions.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `subscriptions` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`user_id` INT NOT NULL,
|
||||
`stripe_subscription_id` VARCHAR(255) NOT NULL,
|
||||
`plan` VARCHAR(50) NOT NULL,
|
||||
`status` VARCHAR(50) NOT NULL,
|
||||
`start_date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`end_date` TIMESTAMP NULL DEFAULT NULL,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
";
|
||||
$pdo->exec($sql);
|
||||
echo "Table 'subscriptions' created successfully.";
|
||||
} catch (PDOException $e) {
|
||||
die("Could not create table 'subscriptions': " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
20
db/setup_users.php
Normal file
20
db/setup_users.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
require_once 'config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
email VARCHAR(255) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
";
|
||||
$pdo->exec($sql);
|
||||
echo "Table 'users' created successfully.";
|
||||
} catch (PDOException $e) {
|
||||
die("DB ERROR: " . $e->getMessage());
|
||||
}
|
||||
?>
|
||||
254
index.php
254
index.php
@ -1,150 +1,120 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
@ini_set('display_errors', '1');
|
||||
@error_reporting(E_ALL);
|
||||
@date_default_timezone_set('UTC');
|
||||
|
||||
$phpVersion = PHP_VERSION;
|
||||
$now = date('Y-m-d H:i:s');
|
||||
<?php
|
||||
$projectName = $_SERVER['PROJECT_NAME'] ?? 'Sacred Habits';
|
||||
$projectDesc = $_SERVER['PROJECT_DESCRIPTION'] ?? 'A 90-second daily ritual to reprogram your inner voice.';
|
||||
$projectImage = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
|
||||
$themes = [
|
||||
['name' => 'Safety', 'color' => '#34D399'],
|
||||
['name' => 'Permission', 'color' => '#FBBF24'],
|
||||
['name' => 'Possibility', 'color' => '#60A5FA'],
|
||||
['name' => 'Presence', 'color' => '#A78BFA'],
|
||||
['name' => 'Enoughness', 'color' => '#F472B6'],
|
||||
['name' => 'Trust', 'color' => '#2DD4BF'],
|
||||
['name' => 'Release', 'color' => '#F87171'],
|
||||
['name' => 'Prosperity', 'color' => '#38B2AC', 'premium' => true],
|
||||
['name' => 'Wellness', 'color' => '#4ADE80', 'premium' => true],
|
||||
['name' => 'Spirituality', 'color' => '#818CF8', 'premium' => true],
|
||||
];
|
||||
|
||||
?>
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>New Style</title>
|
||||
<?php
|
||||
// Read project preview data from environment
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
?>
|
||||
<?php if ($projectDescription): ?>
|
||||
<!-- Meta description -->
|
||||
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
|
||||
<!-- Open Graph meta tags -->
|
||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<!-- Twitter meta tags -->
|
||||
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<?php endif; ?>
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<!-- Open Graph image -->
|
||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<!-- Twitter image -->
|
||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
@keyframes bg-pan {
|
||||
0% { background-position: 0% 0%; }
|
||||
100% { background-position: 100% 100%; }
|
||||
}
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.loader {
|
||||
margin: 1.25rem auto 1.25rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.hint {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; border: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
code {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo htmlspecialchars($projectName); ?></title>
|
||||
<meta name="description" content="<?php echo htmlspecialchars($projectDesc); ?>">
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="<?php echo (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; ?>">
|
||||
<meta property="og:title" content="<?php echo htmlspecialchars($projectName); ?>">
|
||||
<meta property="og:description" content="<?php echo htmlspecialchars($projectDesc); ?>">
|
||||
<meta property="og:image" content="<?php echo htmlspecialchars($projectImage); ?>">
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta property="twitter:card" content="summary_large_image">
|
||||
<meta property="twitter:url" content="<?php echo (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST']; ?>">
|
||||
<meta property="twitter:title" content="<?php echo htmlspecialchars($projectName); ?>">
|
||||
<meta property="twitter:description" content="<?php echo htmlspecialchars($projectDesc); ?>">
|
||||
<meta property="twitter:image" content="<?php echo htmlspecialchars($projectImage); ?>">
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your website…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
</div>
|
||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
||||
<?php session_start(); ?>
|
||||
<body class="d-flex flex-column min-vh-100">
|
||||
<div class="container my-5">
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="index.php"><?php echo htmlspecialchars($projectName); ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<li class="nav-item">
|
||||
<span class="navbar-text me-3">Welcome, <?php echo htmlspecialchars($_SESSION['user_name']); ?>!</span>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="progress.php">Progress</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="pricing.php">Subscribe</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">Logout</a>
|
||||
</li>
|
||||
<?php else: ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="login.php">Login</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="register.php">Register</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<?php
|
||||
// Simulate checking subscription status
|
||||
$has_subscription = isset($_SESSION['has_subscription']) && $_SESSION['has_subscription'];
|
||||
?>
|
||||
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 g-4">
|
||||
<?php foreach ($themes as $theme): ?>
|
||||
<?php
|
||||
$is_premium = isset($theme['premium']) && $theme['premium'];
|
||||
$can_access = !$is_premium || ($is_premium && $has_subscription);
|
||||
$link = $can_access ? 'ritual.php?theme=' . urlencode($theme['name']) : 'pricing.php';
|
||||
$card_class = $can_access ? '' : 'disabled-theme';
|
||||
?>
|
||||
<div class="col">
|
||||
<a href="<?php echo $link; ?>" class="text-decoration-none">
|
||||
<div class="card h-100 theme-card <?php echo $card_class; ?>" style="border-top: 5px solid <?php echo $theme['color']; ?>;">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title mb-0">
|
||||
<?php echo htmlspecialchars($theme['name']); ?>
|
||||
<?php if ($is_premium): ?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-lock-fill" viewBox="0 0 16 16">
|
||||
<path d="M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z"/>
|
||||
</svg>
|
||||
<?php endif; ?>
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
||||
</footer>
|
||||
|
||||
<footer class="text-center mt-5 py-4 text-muted">
|
||||
<p>© <?php echo date('Y'); ?> <?php echo htmlspecialchars($projectName); ?>. All rights reserved.</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
34
log_progress.php
Normal file
34
log_progress.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
require_once 'db/config.php';
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
http_response_code(401); // Unauthorized
|
||||
exit('You must be logged in to log progress.');
|
||||
}
|
||||
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$theme = $data['theme'] ?? null;
|
||||
|
||||
if (empty($theme)) {
|
||||
http_response_code(400); // Bad Request
|
||||
exit('Theme is required.');
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$completion_date = date('Y-m-d');
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("INSERT INTO progress (user_id, theme, completion_date) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$user_id, $theme, $completion_date]);
|
||||
|
||||
http_response_code(200); // OK
|
||||
echo json_encode(['success' => true]);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500); // Internal Server Error
|
||||
error_log('Failed to log progress: ' . $e->getMessage());
|
||||
echo json_encode(['success' => false, 'message' => 'Could not save progress.']);
|
||||
}
|
||||
112
login.php
Normal file
112
login.php
Normal file
@ -0,0 +1,112 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
if (isset($_SESSION['success_message'])) {
|
||||
$success = $_SESSION['success_message'];
|
||||
unset($_SESSION['success_message']);
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$email = trim($_POST['email']);
|
||||
$password = $_POST['password'];
|
||||
|
||||
if (empty($email) || empty($password)) {
|
||||
$error = 'Please fill in all fields.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$sql = 'SELECT * FROM users WHERE email = ?';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$email]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['user_name'] = $user['name'];
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = 'Invalid email or password.';
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - Sacred Habits</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body class="d-flex flex-column min-vh-100">
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="index.php">Sacred Habits</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="register.php">Register</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-center">Login to Your Account</h2>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo $error; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($success)): ?>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<?php echo $success; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form action="login.php" method="POST">
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email address</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="footer mt-auto py-3 bg-light">
|
||||
<div class="container text-center">
|
||||
<span class="text-muted">© 2025 Sacred Habits</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
7
logout.php
Normal file
7
logout.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
session_start();
|
||||
session_unset();
|
||||
session_destroy();
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
?>
|
||||
130
pricing.php
Normal file
130
pricing.php
Normal file
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
if (isset($_GET['simulate'])) {
|
||||
$_SESSION['has_subscription'] = $_GET['simulate'] === 'true';
|
||||
header('Location: pricing.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once 'db/config.php';
|
||||
$project_name = getenv('PROJECT_NAME') ?: 'Ritual';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pricing - <?php echo htmlspecialchars($project_name); ?></title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<a class="navbar-brand" href="index.php"><?php echo htmlspecialchars($project_name); ?></a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Welcome, <?php echo htmlspecialchars($_SESSION['username']); ?></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="progress.php">Progress</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">Logout</a>
|
||||
</li>
|
||||
<?php else: ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="login.php">Login</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="register.php">Register</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-5">
|
||||
<div class="text-center">
|
||||
<h1>Choose Your Plan</h1>
|
||||
<p class="lead">Unlock premium features and support the development of this platform.</p>
|
||||
</div>
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h4 class="my-0 font-weight-normal">Basic</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h1 class="card-title pricing-card-title">$5 <small class="text-muted">/ mo</small></h1>
|
||||
<ul class="list-unstyled mt-3 mb-4">
|
||||
<li>Access to all themes</li>
|
||||
<li>Track your progress</li>
|
||||
<li>Email support</li>
|
||||
</ul>
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<a href="checkout.php?plan=basic" class="btn btn-lg btn-block btn-outline-primary">Sign up for Basic</a>
|
||||
<?php else: ?>
|
||||
<a href="login.php" class="btn btn-lg btn-block btn-primary">Login to Subscribe</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h4 class="my-0 font-weight-normal">Pro</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h1 class="card-title pricing-card-title">$15 <small class="text-muted">/ mo</small></h1>
|
||||
<ul class="list-unstyled mt-3 mb-4">
|
||||
<li>All Basic features</li>
|
||||
<li>Access to premium themes</li>
|
||||
<li>Priority email support</li>
|
||||
</ul>
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<a href="checkout.php?plan=pro" class="btn btn-lg btn-block btn-primary">Get started</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card mb-4 shadow-sm">
|
||||
<div class="card-header">
|
||||
<h4 class="my-0 font-weight-normal">Enterprise</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h1 class="card-title pricing-card-title">$29 <small class="text-muted">/ mo</small></h1>
|
||||
<ul class="list-unstyled mt-3 mb-4">
|
||||
<li>All Pro features</li>
|
||||
<li>24/7 phone support</li>
|
||||
<li>Dedicated account manager</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<div class="mt-5 p-4 bg-light rounded">
|
||||
<h3>Subscription Simulation (for testing)</h3>
|
||||
<p>You can simulate having a subscription to test the premium features.</p>
|
||||
<a href="pricing.php?simulate=true" class="btn btn-success">Simulate Subscription</a>
|
||||
<a href="pricing.php?simulate=false" class="btn btn-danger">Cancel Simulation</a>
|
||||
<p class="mt-2">Current status: <strong><?php echo isset($_SESSION['has_subscription']) && $_SESSION['has_subscription'] ? 'Active' : 'Inactive'; ?></strong></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
155
progress.php
Normal file
155
progress.php
Normal file
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
require_once 'db/config.php';
|
||||
$pdo = db();
|
||||
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
// Fetch progress data
|
||||
$stmt = $pdo->prepare("SELECT theme, completion_date FROM progress WHERE user_id = ? ORDER BY completion_date DESC");
|
||||
$stmt->execute([$user_id]);
|
||||
$progress_data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// --- Progress Calculation ---
|
||||
|
||||
// 1. Last 7 Days Grid
|
||||
$last_7_days = [];
|
||||
for ($i = 0; $i < 7; $i++) {
|
||||
$date = date('Y-m-d', strtotime("-$i days"));
|
||||
$last_7_days[$date] = false;
|
||||
}
|
||||
|
||||
foreach ($progress_data as $progress) {
|
||||
if (isset($last_7_days[$progress['completion_date']])) {
|
||||
$last_7_days[$progress['completion_date']] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Total Practices
|
||||
$total_practices = count($progress_data);
|
||||
|
||||
// 3. Current Streak
|
||||
$current_streak = 0;
|
||||
if ($total_practices > 0) {
|
||||
$dates = array_unique(array_column($progress_data, 'completion_date'));
|
||||
rsort($dates);
|
||||
$current_streak = 1;
|
||||
$today = date('Y-m-d');
|
||||
$yesterday = date('Y-m-d', strtotime('-1 day'));
|
||||
|
||||
if ($dates[0] != $today && $dates[0] != $yesterday) {
|
||||
$current_streak = 0;
|
||||
} else {
|
||||
for ($i = 0; $i < count($dates) - 1; $i++) {
|
||||
$date1 = new DateTime($dates[$i]);
|
||||
$date2 = new DateTime($dates[$i+1]);
|
||||
$diff = $date1->diff($date2)->days;
|
||||
if ($diff == 1) {
|
||||
$current_streak++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Practiced Themes
|
||||
$practiced_themes = array_unique(array_column($progress_data, 'theme'));
|
||||
|
||||
$project_name = getenv('PROJECT_NAME') ?: 'Mindful Moments';
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Your Progress - <?php echo htmlspecialchars($project_name); ?></title>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
<style>
|
||||
.progress-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(7, 1fr);
|
||||
gap: 10px;
|
||||
}
|
||||
.day-box {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 1px solid #ccc;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
.day-box.completed {
|
||||
background-color: #d4edda;
|
||||
}
|
||||
.day-initial {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include 'index.php'; ?>
|
||||
|
||||
<div class="container mt-5">
|
||||
<h2>Your Progress</h2>
|
||||
|
||||
<div class="row mt-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">Total Practices</h5>
|
||||
<p class="card-text display-4"><?php echo $total_practices; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-body text-center">
|
||||
<h5 class="card-title">Current Streak</h5>
|
||||
<p class="card-text display-4"><?php echo $current_streak; ?> <?php echo ($current_streak == 1) ? 'day' : 'days'; ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<h5>Last 7 Days</h5>
|
||||
<div class="progress-grid">
|
||||
<?php foreach ($last_7_days as $date => $completed): ?>
|
||||
<div class="day-box <?php echo $completed ? 'completed' : ''; ?>">
|
||||
<span class="day-initial"><?php echo date('D', strtotime($date)); ?></span>
|
||||
<span><?php echo date('d', strtotime($date)); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-5">
|
||||
<h5>Practiced Themes</h5>
|
||||
<?php if (empty($practiced_themes)): ?>
|
||||
<p>You haven't completed any rituals yet.</p>
|
||||
<?php else: ?>
|
||||
<ul class="list-group">
|
||||
<?php foreach ($practiced_themes as $theme): ?>
|
||||
<li class="list-group-item"><?php echo htmlspecialchars($theme); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
111
register.php
Normal file
111
register.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once 'db/config.php';
|
||||
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$name = trim($_POST['name']);
|
||||
$email = trim($_POST['email']);
|
||||
$password = $_POST['password'];
|
||||
|
||||
if (empty($name) || empty($email) || empty($password)) {
|
||||
$error = 'Please fill in all fields.';
|
||||
} else {
|
||||
try {
|
||||
$pdo = db();
|
||||
|
||||
$sql = 'SELECT id FROM users WHERE email = ?';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$email]);
|
||||
if ($stmt->fetch()) {
|
||||
$error = 'Email is already registered.';
|
||||
} else {
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$sql = 'INSERT INTO users (name, email, password) VALUES (?, ?, ?)';
|
||||
$stmt = $pdo->prepare($sql);
|
||||
if ($stmt->execute([$name, $email, $hashed_password])) {
|
||||
$_SESSION['success_message'] = 'Registration successful! Please login.';
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = 'Something went wrong. Please try again.';
|
||||
}
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
$error = 'Database error: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Register - Sacred Habits</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css">
|
||||
</head>
|
||||
<body class="d-flex flex-column min-vh-100">
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="index.php">Sacred Habits</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="login.php">Login</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-center">Create Your Account</h2>
|
||||
<?php if (!empty($error)): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo $error; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<form action="register.php" method="POST">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Name</label>
|
||||
<input type="text" class="form-control" id="name" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email address</label>
|
||||
<input type="email" class="form-control" id="email" name="email" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Register</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer class="footer mt-auto py-3 bg-light">
|
||||
<div class="container text-center">
|
||||
<span class="text-muted">© 2025 Sacred Habits</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
149
ritual.php
Normal file
149
ritual.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php session_start(); ?>
|
||||
<?php
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Sanitize theme input
|
||||
$theme = filter_input(INPUT_GET, 'theme', FILTER_SANITIZE_STRING);
|
||||
if (empty($theme)) {
|
||||
$theme = 'gratitude'; // Default theme
|
||||
}
|
||||
|
||||
$level = 'beginner'; // Hardcoded for now, will be dynamic later
|
||||
|
||||
$affirmation_text = 'Your default affirmation text goes here. You are capable of amazing things.';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
// Fetch a random affirmation for the given theme and level
|
||||
$stmt = $pdo->prepare(
|
||||
"SELECT affirmation_text FROM affirmations WHERE theme = :theme AND level = :level ORDER BY RAND() LIMIT 1"
|
||||
);
|
||||
$stmt->execute(['theme' => $theme, 'level' => $level]);
|
||||
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($result && !empty($result['affirmation_text'])) {
|
||||
$affirmation_text = $result['affirmation_text'];
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
// Log the error instead of displaying it to the user
|
||||
error_log("Database error in ritual.php: " . $e->getMessage());
|
||||
// The page will proceed with the default affirmation text
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Sacred Habits - Ritual</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<?php $projectName = $_SERVER['PROJECT_NAME'] ?? 'Sacred Habits'; ?>
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="index.php"><?php echo htmlspecialchars($projectName); ?></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<?php if (isset($_SESSION['user_id'])): ?>
|
||||
<li class="nav-item">
|
||||
<span class="navbar-text me-3">Welcome, <?php echo htmlspecialchars($_SESSION['user_name']); ?>!</span>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="progress.php">Progress</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="pricing.php">Subscribe</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="logout.php">Logout</a>
|
||||
</li>
|
||||
<?php else: ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="login.php">Login</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="register.php">Register</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container my-5">
|
||||
<div class="progress-bar-container mb-4">
|
||||
<div class="progress-bar-fill"></div>
|
||||
</div>
|
||||
|
||||
<!-- Step 0: Intro -->
|
||||
<div class="ritual-step active text-center">
|
||||
<h1 class="mb-3">Your 90-Second Ritual</h1>
|
||||
<p class="lead text-muted mb-4">A moment for yourself, inspired by the theme of <strong><?php echo htmlspecialchars(ucfirst($theme)); ?></strong>.</p>
|
||||
<button id="begin-ritual" class="btn btn-primary btn-lg">Begin Ritual</button>
|
||||
</div>
|
||||
|
||||
<!-- Step 1: Release -->
|
||||
<div class="ritual-step text-center">
|
||||
<i data-feather="x-circle" class="mb-3" style="width: 48px; height: 48px; color: #EC4899;"></i>
|
||||
<h2 class="mb-3">Release</h2>
|
||||
<p class="lead">Let go of what no longer serves you. Take a deep breath out.</p>
|
||||
<div id="timer" class="timer text-primary">01:30</div>
|
||||
<button class="btn btn-secondary next-step mt-4">Next</button>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: Receive -->
|
||||
<div class="ritual-step text-center">
|
||||
<i data-feather="arrow-down-circle" class="mb-3" style="width: 48px; height: 48px; color: #6366F1;"></i>
|
||||
<h2 class="mb-3">Receive</h2>
|
||||
<p class="lead">Open yourself to new energy and possibility. Breathe in deeply.</p>
|
||||
<button class="btn btn-primary next-step mt-4">Next</button>
|
||||
</div>
|
||||
|
||||
<!-- Step 3: Practice -->
|
||||
<div class="ritual-step text-center">
|
||||
<i data-feather="heart" class="mb-3" style="width: 48px; height: 48px; color: #EC4899;"></i>
|
||||
<h2 class="mb-3">Practice</h2>
|
||||
<p class="lead">Repeat the affirmation, feeling its truth resonate within you.</p>
|
||||
<blockquote class="blockquote fs-4 my-4">"<?php echo htmlspecialchars($affirmation_text); ?>"</blockquote>
|
||||
<button class="btn btn-secondary next-step mt-4">Next</button>
|
||||
</div>
|
||||
|
||||
<!-- Step 4: Breathe -->
|
||||
<div class="ritual-step text-center">
|
||||
<i data-feather="wind" class="mb-3" style="width: 48px; height: 48px; color: #6366F1;"></i>
|
||||
<h2 class="mb-3">Breathe</h2>
|
||||
<p class="lead">Integrate the practice with your breath. Inhale peace, exhale gratitude.</p>
|
||||
<button class="btn btn-primary next-step mt-4">Next</button>
|
||||
</div>
|
||||
|
||||
<!-- Step 5: Affirm -->
|
||||
<div class="ritual-step text-center">
|
||||
<i data-feather="check-circle" class="mb-3" style="width: 48px; height: 48px; color: #10B981;"></i>
|
||||
<h2 class="mb-3">Affirm</h2>
|
||||
<p class="lead">Lock in the feeling with one final repetition.</p>
|
||||
<blockquote class="blockquote fs-4 my-4 text-primary">"<?php echo htmlspecialchars($affirmation_text); ?>"</blockquote>
|
||||
<button class="btn btn-secondary next-step mt-4">Complete</button>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Step 6: Celebration -->
|
||||
<div class="ritual-step text-center">
|
||||
<h1 class="display-3 text-primary">✨ Ritual Complete! ✨</h1>
|
||||
<p class="lead">You have honored your commitment to yourself.</p>
|
||||
<a href="index.php" class="btn btn-primary mt-4">Back to Themes</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
|
||||
<script>
|
||||
feather.replace();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
81
webhook.php
Normal file
81
webhook.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
// Include the Stripe PHP library (assuming it's installed via Composer)
|
||||
// require_once 'vendor/autoload.php';
|
||||
|
||||
require_once 'db/config.php';
|
||||
|
||||
// Set your Stripe API key and webhook secret
|
||||
// \Stripe\Stripe::setApiKey('YOUR_STRIPE_SECRET_KEY');
|
||||
$webhook_secret = 'YOUR_STRIPE_WEBHOOK_SECRET';
|
||||
|
||||
$payload = @file_get_contents('php://input');
|
||||
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
|
||||
$event = null;
|
||||
|
||||
/*
|
||||
try {
|
||||
$event = \Stripe\Webhook::constructEvent(
|
||||
$payload, $sig_header, $webhook_secret
|
||||
);
|
||||
} catch(\UnexpectedValueException $e) {
|
||||
// Invalid payload
|
||||
http_response_code(400);
|
||||
exit();
|
||||
} catch(\Stripe\Exception\SignatureVerificationException $e) {
|
||||
// Invalid signature
|
||||
http_response_code(400);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Handle the event
|
||||
switch ($event->type) {
|
||||
case 'checkout.session.completed':
|
||||
$session = $event->data->object;
|
||||
$user_id = $session->client_reference_id;
|
||||
$stripe_subscription_id = $session->subscription;
|
||||
|
||||
// Get subscription details
|
||||
$stripe = new \Stripe\StripeClient('YOUR_STRIPE_SECRET_KEY');
|
||||
$subscription = $stripe->subscriptions->retrieve($stripe_subscription_id, []);
|
||||
$plan = $subscription->items->data[0]->price->nickname;
|
||||
|
||||
// Store subscription in the database
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("INSERT INTO subscriptions (user_id, stripe_subscription_id, plan, status, start_date, end_date) VALUES (?, ?, ?, ?, FROM_UNIXTIME(?), FROM_UNIXTIME(?))");
|
||||
$stmt->execute([
|
||||
$user_id,
|
||||
$stripe_subscription_id,
|
||||
$plan,
|
||||
$subscription->status,
|
||||
$subscription->current_period_start,
|
||||
$subscription->current_period_end
|
||||
]);
|
||||
} catch (PDOException $e) {
|
||||
// Log error
|
||||
error_log("Webhook DB Error: " . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
case 'customer.subscription.updated':
|
||||
$subscription = $event->data->object;
|
||||
$stripe_subscription_id = $subscription->id;
|
||||
$status = $subscription->status;
|
||||
$end_date = $subscription->cancel_at_period_end ? $subscription->current_period_end : null;
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare("UPDATE subscriptions SET status = ?, end_date = FROM_UNIXTIME(?) WHERE stripe_subscription_id = ?");
|
||||
$stmt->execute([$status, $end_date, $stripe_subscription_id]);
|
||||
} catch (PDOException $e) {
|
||||
// Log error
|
||||
error_log("Webhook DB Error: " . $e->getMessage());
|
||||
}
|
||||
break;
|
||||
// ... handle other event types
|
||||
default:
|
||||
// Unexpected event type
|
||||
}
|
||||
*/
|
||||
|
||||
http_response_code(200);
|
||||
?>
|
||||
Loading…
x
Reference in New Issue
Block a user