diff --git a/auth/register_handler.php b/auth/register_handler.php index 7ae50c1..9eabf02 100644 --- a/auth/register_handler.php +++ b/auth/register_handler.php @@ -1,4 +1,5 @@ prepare("INSERT INTO users (email, password, role) VALUES (?, ?, ?)"); - $stmt->execute([$email, $hashed_password, 'FREE_USER']); + $stmt->execute([$email, $hashed_password, 'free']); - header('Location: /login.php?success=registered'); + $new_user_id = $pdo->lastInsertId(); + + // Check for guest CV data and save it + if (isset($_SESSION['guest_cv_data'])) { + $cv_data = $_SESSION['guest_cv_data']; + $title = $cv_data['title'] ?? 'My CV'; + $template_id = $cv_data['template_id'] ?? 1; + $content = json_encode([ + 'personal_info' => $cv_data['personal_info'] ?? [], + 'experience' => array_values($cv_data['experience'] ?? []), + 'education' => array_values($cv_data['education'] ?? []), + 'skills' => $cv_data['skills'] ?? '' + ]); + + $cv_stmt = $pdo->prepare('INSERT INTO cvs (user_id, title, content, template_id) VALUES (?, ?, ?, ?)'); + $cv_stmt->execute([$new_user_id, $title, $content, $template_id]); + + unset($_SESSION['guest_cv_data']); + } + + // Log the user in automatically + $_SESSION['user_id'] = $new_user_id; + $_SESSION['user_email'] = $email; + $_SESSION['user_role'] = 'free'; // Default role + + // Redirect to dashboard + header('Location: /dashboard.php'); exit; } catch (PDOException $e) { @@ -34,4 +61,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { header('Location: /register.php?error=db_error'); exit; } -} +} \ No newline at end of file diff --git a/cv_editor.php b/cv_editor.php new file mode 100644 index 0000000..094f19c --- /dev/null +++ b/cv_editor.php @@ -0,0 +1,178 @@ +query('SELECT id, name, is_premium FROM templates WHERE is_premium = 0'); +} else { + // Pro and Admin users can see all templates + $templates_stmt = $pdo->query('SELECT id, name, is_premium FROM templates'); +} +$templates = $templates_stmt->fetchAll(PDO::FETCH_ASSOC); + +$cv_data = [ + 'id' => null, + 'title' => 'My CV', + 'content' => json_encode([ + 'personal_info' => ['name' => '', 'email' => '', 'phone' => '', 'linkedin' => '' ], + 'experience' => [], + 'education' => [], + 'skills' => '' + ]), + 'template_id' => null +]; + +if (isset($_GET['id'])) { + $stmt = $pdo->prepare('SELECT * FROM cvs WHERE id = :id AND user_id = :user_id'); + $stmt->execute(['id' => $_GET['id'], 'user_id' => $_SESSION['user_id']]); + $cv = $stmt->fetch(PDO::FETCH_ASSOC); + if ($cv) { + $cv_data = $cv; + } +} + +$content = json_decode($cv_data['content'], true); +require_once __DIR__ . '/includes/header.php'; +?> + +
+

+
+ + +
+ + +
+ +
+ + +
+ +
+ Personal Information +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ Work Experience +
+ $exp): + ?> +
+ + + +
+ +
+ +
+ +
+ Education +
+ $edu): + ?> +
+ + +
+ +
+ +
+ +
+ Skills +
+ +
+
+ + +
+
+ + + + \ No newline at end of file diff --git a/dashboard.php b/dashboard.php index d9effe1..638676b 100644 --- a/dashboard.php +++ b/dashboard.php @@ -8,16 +8,54 @@ if (!isset($_SESSION['user_id'])) { } require_once __DIR__ . '/includes/header.php'; + +// Check for and display error messages +if (isset($_SESSION['error_message'])) { + echo '

' . htmlspecialchars($_SESSION['error_message']) . '

'; + unset($_SESSION['error_message']); // Clear the message after displaying +} + +// Check for and display success messages +if (isset($_SESSION['success_message'])) { + echo '

' . htmlspecialchars($_SESSION['success_message']) . '

'; + unset($_SESSION['success_message']); // Clear the message after displaying +} ?>

Welcome to Your Dashboard

-

Your role:

+

Your role:

Your CVs

-

You don't have any CVs yet.

- Create a New CV + prepare('SELECT id, title, updated_at FROM cvs WHERE user_id = :user_id ORDER BY updated_at DESC'); + $stmt->execute(['user_id' => $_SESSION['user_id']]); + $cvs = $stmt->fetchAll(PDO::FETCH_ASSOC); + + if ($cvs): + ?> + + +

You don't have any CVs yet. Let's create one!

+ + Create a New CV
Logout diff --git a/db/migrations/002_add_templates.sql b/db/migrations/002_add_templates.sql new file mode 100644 index 0000000..1e65199 --- /dev/null +++ b/db/migrations/002_add_templates.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS `templates` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `name` VARCHAR(255) NOT NULL, + `description` TEXT, + `file_path` VARCHAR(255) NOT NULL, + `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +ALTER TABLE `cvs` ADD COLUMN `template_id` INT NULL; + +-- Insert some default templates +INSERT INTO `templates` (`name`, `description`, `file_path`) VALUES +('Minimalist', 'A clean and simple template.', 'minimalist.php'), +('Professional', 'A classic and professional template.', 'professional.php'); diff --git a/db/migrations/003_add_roles_and_premium_templates.sql b/db/migrations/003_add_roles_and_premium_templates.sql new file mode 100644 index 0000000..565c2f6 --- /dev/null +++ b/db/migrations/003_add_roles_and_premium_templates.sql @@ -0,0 +1,8 @@ +-- Add role to users table +ALTER TABLE `users` ADD `role` VARCHAR(50) NOT NULL DEFAULT 'free'; + +-- Add is_premium to templates table +ALTER TABLE `templates` ADD `is_premium` BOOLEAN NOT NULL DEFAULT FALSE; + +-- Set the "Professional" template as premium for demonstration +UPDATE `templates` SET `is_premium` = TRUE WHERE `name` = 'Professional'; diff --git a/delete_cv.php b/delete_cv.php new file mode 100644 index 0000000..4bf851e --- /dev/null +++ b/delete_cv.php @@ -0,0 +1,45 @@ +prepare("SELECT user_id FROM cvs WHERE id = ?"); + $stmt->execute([$cv_id]); + $cv = $stmt->fetch(PDO::FETCH_ASSOC); + + if (!$cv || $cv['user_id'] != $user_id) { + // CV not found or does not belong to the user + header('Location: dashboard.php?error=CV not found or permission denied.'); + exit(); + } + + // Delete the CV + $stmt = $pdo->prepare("DELETE FROM cvs WHERE id = ? AND user_id = ?"); + $stmt->execute([$cv_id, $user_id]); + + header('Location: dashboard.php?success=CV deleted successfully.'); + exit(); + +} catch (PDOException $e) { + // Log error and redirect + error_log("CV Deletion Error: " . $e->getMessage()); + header('Location: dashboard.php?error=An error occurred while deleting the CV.'); + exit(); +} +?> \ No newline at end of file diff --git a/includes/header.php b/includes/header.php index 2b5aab6..2a8210b 100644 --- a/includes/header.php +++ b/includes/header.php @@ -1,21 +1,36 @@ + - MagiCV + <?php echo isset($pageTitle) ? $pageTitle . ' - MagiCV' : 'MagiCV'; ?> +
-
+
\ No newline at end of file diff --git a/payment_handler.php b/payment_handler.php new file mode 100644 index 0000000..6770746 --- /dev/null +++ b/payment_handler.php @@ -0,0 +1,27 @@ +prepare($sql); + +if ($stmt->execute([$user_id])) { + // Update role in session + $_SESSION['role'] = 'pro'; + $_SESSION['success_message'] = "Congratulations! You have successfully upgraded to the PRO plan."; +} else { + $_SESSION['error_message'] = "Something went wrong during the upgrade. Please try again."; +} + +header('Location: dashboard.php'); +exit(); diff --git a/public/css/style.css b/public/css/style.css index 3e1582d..a3b36bb 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -16,6 +16,15 @@ main { padding: 2rem; } +.container { + max-width: 800px; + margin: 2rem auto; + padding: 2rem; + background: #fff; + border: 1px solid #eaeaea; + border-radius: 8px; +} + /* Header and Navigation */ header { background: #fff; @@ -140,22 +149,27 @@ footer { margin-bottom: 0.5rem; } -.form-group input { +.form-group input, .form-group textarea { width: 100%; padding: 0.75rem; border: 1px solid #ccc; border-radius: 5px; } -.auth-container .button { - width: 100%; - padding: 0.75rem; +.button { + display: inline-block; + padding: 0.75rem 1.5rem; border: none; border-radius: 5px; background-color: #6c63ff; color: #fff; font-size: 1rem; cursor: pointer; + text-decoration: none; +} + +.auth-container .button { + width: 100%; } .auth-container p { @@ -163,9 +177,135 @@ footer { margin-top: 1rem; } +.auth-container .error { + color: #c53030; + background-color: #fed7d7; + padding: 0.75rem; + border-radius: 5px; + margin-bottom: 1rem; + text-align: center; +} + /* Dashboard */ .dashboard-container { max-width: 800px; margin: 2rem auto; padding: 2rem; } + +/* CV List */ +.cv-list { + list-style: none; + margin-top: 1.5rem; +} + +.cv-list li { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; + padding: 1rem; + background: #fff; + border: 1px solid #eaeaea; + border-radius: 5px; + transition: box-shadow 0.3s; +} + +.cv-list li:hover { + box-shadow: 0 2px 8px rgba(0,0,0,0.1); +} + +.cv-item strong { + font-size: 1.2rem; + display: block; + margin-bottom: 0.25rem; +} + +.cv-item span { + font-size: 0.9rem; + color: #777; +} + +.cv-actions { + display: flex; + gap: 0.5rem; +} + +.button-sm { + padding: 0.4rem 0.8rem; + font-size: 0.9rem; + text-decoration: none; + border-radius: 4px; + color: #fff; + background-color: #6c63ff; +} + +.button-danger { + background-color: #e53e3e; +} + +.cv-list a { + text-decoration: none; + color: #333; +} + + +/* CV Editor */ +#cv-form fieldset { + border: 1px solid #eaeaea; + padding: 1.5rem; + border-radius: 8px; + margin-bottom: 1.5rem; +} + +#cv-form legend { + font-weight: bold; + padding: 0 0.5rem; + margin-left: 1rem; +} + +.experience-item, .education-item { + margin-bottom: 1rem; + padding: 1rem; + border: 1px solid #f0f0f0; + border-radius: 5px; +} + +#add-experience, #add-education { + margin-top: 1rem; + background: none; + border: 1px dashed #ccc; + color: #555; + padding: 0.5rem 1rem; + cursor: pointer; +} + +/* Banners */ +.error-banner { + background-color: #fed7d7; + color: #c53030; + padding: 1rem; + border: 1px solid #fbcaca; + border-radius: 5px; + margin-bottom: 1.5rem; + text-align: center; +} +.auth-container .info { + color: #004085; + background-color: #cce5ff; + padding: 0.75rem; + border-radius: 5px; + margin-bottom: 1rem; + text-align: center; +} + +.success-banner { + background-color: #d4edda; + color: #155724; + padding: 1rem; + border: 1px solid #c3e6cb; + border-radius: 5px; + margin-bottom: 1.5rem; + text-align: center; +} + diff --git a/register.php b/register.php index b9645c0..492923a 100644 --- a/register.php +++ b/register.php @@ -1,9 +1,16 @@

Create Your Account

+ + +

+ + +

+?> \ No newline at end of file diff --git a/save_cv.php b/save_cv.php new file mode 100644 index 0000000..a868344 --- /dev/null +++ b/save_cv.php @@ -0,0 +1,75 @@ +prepare("SELECT COUNT(*) FROM cvs WHERE user_id = ?"); + $stmt->execute([$user_id]); + $cv_count = $stmt->fetchColumn(); + + if ($cv_count >= 2) { + // Limit reached for free users + $_SESSION['error_message'] = 'You have reached the maximum of 2 CVs for the Free Plan. Please upgrade to create more.'; + header('Location: /dashboard.php'); + exit; + } + } + + $content = json_encode([ + 'personal_info' => $_POST['personal_info'] ?? [], + 'experience' => array_values($_POST['experience'] ?? []), + 'education' => array_values($_POST['education'] ?? []), + 'skills' => $_POST['skills'] ?? '' + ]); + + if ($cv_id) { + // Update existing CV + $stmt = $pdo->prepare('UPDATE cvs SET title = :title, content = :content, template_id = :template_id, updated_at = NOW() WHERE id = :id AND user_id = :user_id'); + $stmt->execute([ + 'id' => $cv_id, + 'user_id' => $user_id, + 'title' => $title, + 'content' => $content, + 'template_id' => $template_id + ]); + } else { + // Insert new CV + $stmt = $pdo->prepare('INSERT INTO cvs (user_id, title, content, template_id) VALUES (:user_id, :title, :content, :template_id)'); + $stmt->execute([ + 'user_id' => $user_id, + 'title' => $title, + 'content' => $content, + 'template_id' => $template_id + ]); + } + + header('Location: /dashboard.php'); + exit; +} else { + // Not a POST request + header('Location: /dashboard.php'); + exit; +} \ No newline at end of file diff --git a/templates/minimalist.php b/templates/minimalist.php new file mode 100644 index 0000000..b527cf4 --- /dev/null +++ b/templates/minimalist.php @@ -0,0 +1,36 @@ + + + + + + CV: <?php echo htmlspecialchars($cv['title']); ?> + + + +

+
+

name); ?>

+

email); ?> | phone); ?>

+
+
+

Work Experience

+

experience)); ?>

+
+
+

Education

+

education)); ?>

+
+
+

Skills

+

skills)); ?>

+
+
+ + diff --git a/templates/professional.php b/templates/professional.php new file mode 100644 index 0000000..0bf6244 --- /dev/null +++ b/templates/professional.php @@ -0,0 +1,39 @@ + + + + + + CV: <?php echo htmlspecialchars($cv['title']); ?> + + + +
+
+

name); ?>

+
+

email); ?> | phone); ?>

+
+
+
+

Work Experience

+
experience)); ?>
+
+
+

Education

+
education)); ?>
+
+
+

Skills

+
skills)); ?>
+
+
+ + diff --git a/templates_preview.php b/templates_preview.php new file mode 100644 index 0000000..3e3b5ec --- /dev/null +++ b/templates_preview.php @@ -0,0 +1,39 @@ +query("SELECT * FROM templates ORDER BY name"); +$templates = $stmt->fetchAll(); +?> + +
+

CV Templates

+

Browse our library of professionally designed templates. Sign up to use them!

+ +
+ +
+
+ <?php echo htmlspecialchars($template['name']); ?> +
+
+ + + PRO + + FREE + +
+

+
+ +
+
+ +
+
+ + diff --git a/upgrade.php b/upgrade.php new file mode 100644 index 0000000..2940f9f --- /dev/null +++ b/upgrade.php @@ -0,0 +1,33 @@ + + +
+
+

Upgrade to PRO

+

Unlock premium features and take your CV to the next level.

+ +
+

PRO Plan Benefits:

+
    +
  • Unlimited CVs
  • +
  • Access to all premium templates
  • +
  • Priority Support
  • +
+
+ +
+

Click the button below to simulate the upgrade process.

+ +
+
+
+ + diff --git a/view_cv.php b/view_cv.php new file mode 100644 index 0000000..f90c951 --- /dev/null +++ b/view_cv.php @@ -0,0 +1,72 @@ +prepare("SELECT * FROM cvs WHERE id = ? AND user_id = ?"); +$stmt->execute([$cv_id, $user_id]); +$cv = $stmt->fetch(); + +if (!$cv) { + header('Location: dashboard.php'); + exit(); +} + +// Fetch the template +$template_path = null; +if (!empty($cv['template_id'])) { + $stmt = $pdo->prepare("SELECT file_path FROM templates WHERE id = ?"); + $stmt->execute([$cv['template_id']]); + $template = $stmt->fetch(); + if ($template && file_exists(__DIR__ . '/templates/' . $template['file_path'])) { + $template_path = __DIR__ . '/templates/' . $template['file_path']; + } +} + +// If a template is found, render it. Otherwise, fall back to a default view. +if ($template_path) { + // The template file will have access to the $cv variable. + require_once $template_path; +} else { + // Default view if no template is set or found + $cv_data = json_decode($cv['content'], true); +?> + + + + + + View CV: <?php echo htmlspecialchars($cv['title']); ?> + + + +
+

+

Name:

+

Email:

+
+

Work Experience

+
+

Education

+
+

Skills

+

+ Back to Dashboard +
+ + +