190 lines
9.1 KiB
PHP
190 lines
9.1 KiB
PHP
<?php
|
|
require __DIR__ . '/session.php';
|
|
require __DIR__ . '/db.php';
|
|
start_app_session();
|
|
|
|
if (!isset($_SESSION['username']) || !isset($_SESSION['user_id'])) {
|
|
header('Location: /');
|
|
exit;
|
|
}
|
|
|
|
$pdo = getDbConnection();
|
|
|
|
$critterId = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);
|
|
|
|
function fetchOwnedCritter(PDO $pdo, int $userId, int $critterId)
|
|
{
|
|
$stmt = $pdo->prepare('
|
|
SELECT c.id AS id, c.author_id AS author_id, c.isFavorite AS isFavorite, c.isArchived AS isArchived,
|
|
c.adjective_id AS adjective_id, c.noun_id AS noun_id, c.verb_id AS verb_id, c.location_id AS location_id,
|
|
a.value AS adjective, n.value AS noun, v.value AS verb, l.value AS location, c.image AS image
|
|
FROM critters c
|
|
JOIN adjectives a ON a.id = c.adjective_id
|
|
JOIN nouns n ON n.id = c.noun_id
|
|
JOIN verbs v ON v.id = c.verb_id
|
|
JOIN locations l ON l.id = c.location_id
|
|
WHERE c.id = :id AND c.author_id = :author_id
|
|
');
|
|
$stmt->execute(['id' => $critterId, 'author_id' => $userId]);
|
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
|
}
|
|
|
|
$critter = null;
|
|
if ($critterId !== null && $critterId !== false) {
|
|
$critter = fetchOwnedCritter($pdo, (int) $_SESSION['user_id'], $critterId);
|
|
}
|
|
|
|
$isOwner = (bool) $critter;
|
|
|
|
$relatedCritters = [];
|
|
if ($critter) {
|
|
$relatedStmt = $pdo->prepare('
|
|
SELECT id, image FROM critters
|
|
WHERE author_id = :author_id
|
|
AND adjective_id = :adjective_id
|
|
AND noun_id = :noun_id
|
|
AND verb_id = :verb_id
|
|
AND location_id = :location_id
|
|
AND id != :current_id
|
|
ORDER BY id DESC
|
|
');
|
|
$relatedStmt->execute([
|
|
'author_id' => $critter['author_id'],
|
|
'adjective_id' => $critter['adjective_id'],
|
|
'noun_id' => $critter['noun_id'],
|
|
'verb_id' => $critter['verb_id'],
|
|
'location_id' => $critter['location_id'],
|
|
'current_id' => $critter['id'],
|
|
]);
|
|
$relatedCritters = array_values(array_filter(
|
|
$relatedStmt->fetchAll(PDO::FETCH_ASSOC),
|
|
fn($row) => !empty($row['image'])
|
|
));
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $critter && $isOwner && csrf_verify($_POST['csrf_token'] ?? null)) {
|
|
$action = $_POST['action'] ?? '';
|
|
|
|
if ($action === 'toggle_favorite') {
|
|
$newValue = $critter['isFavorite'] ? 0 : 1;
|
|
$stmt = $pdo->prepare('UPDATE critters SET isFavorite = :value WHERE id = :id');
|
|
$stmt->execute(['value' => $newValue, 'id' => $critterId]);
|
|
} elseif ($action === 'toggle_archived') {
|
|
$newValue = $critter['isArchived'] ? 0 : 1;
|
|
$stmt = $pdo->prepare('UPDATE critters SET isArchived = :value WHERE id = :id');
|
|
$stmt->execute(['value' => $newValue, 'id' => $critterId]);
|
|
}
|
|
|
|
header('Location: single-critter.php?id=' . $critterId);
|
|
exit;
|
|
}
|
|
|
|
$pageTitle = 'View Critter';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<?php require __DIR__ . '/lib/head.php'; ?>
|
|
<body class="min-h-screen flex flex-col">
|
|
<?php require __DIR__ . '/lib/header.php'; ?>
|
|
<div class="flex-1 max-w-md mx-auto px-4 py-10 text-center">
|
|
<?php if ($critter): ?>
|
|
<?php if (!empty($critter['image'])): ?>
|
|
<img
|
|
src="critter-images/<?php echo htmlspecialchars($critter['image'], ENT_QUOTES, 'UTF-8'); ?>"
|
|
alt="AI-generated image of this critter"
|
|
class="w-full aspect-square object-cover rounded-lg border border-gray-200 shadow-sm mb-4"
|
|
>
|
|
<?php endif; ?>
|
|
<h1 class="text-2xl font-semibold mb-2">
|
|
<?php echo htmlspecialchars(ucwords($critter['adjective'] . ' ' . $critter['noun']), ENT_QUOTES, 'UTF-8'); ?>
|
|
</h1>
|
|
<p class="text-lg">
|
|
The <?php
|
|
echo htmlspecialchars($critter['adjective'], ENT_QUOTES, 'UTF-8') . ' '
|
|
. htmlspecialchars($critter['noun'], ENT_QUOTES, 'UTF-8') . ' '
|
|
. htmlspecialchars($critter['verb'], ENT_QUOTES, 'UTF-8') . ' '
|
|
. htmlspecialchars($critter['location'], ENT_QUOTES, 'UTF-8');
|
|
?>
|
|
</p>
|
|
<div class="flex justify-center gap-4 mt-6">
|
|
<?php if ($isOwner): ?>
|
|
<form action="single-critter.php?id=<?php echo (int) $critterId; ?>" method="post">
|
|
<?php echo csrf_field(); ?>
|
|
<input type="hidden" name="action" value="toggle_favorite">
|
|
<button
|
|
type="submit"
|
|
class="px-4 py-2 rounded-md font-medium border <?php echo $critter['isFavorite'] ? 'bg-yellow-400 border-yellow-400 text-yellow-950 hover:bg-yellow-500' : 'bg-white border-gray-300 text-gray-800 hover:bg-gray-100'; ?>"
|
|
>
|
|
<?php echo $critter['isFavorite'] ? 'Unfavorite' : 'Favorite'; ?>
|
|
</button>
|
|
</form>
|
|
<form action="single-critter.php?id=<?php echo (int) $critterId; ?>" method="post">
|
|
<?php echo csrf_field(); ?>
|
|
<input type="hidden" name="action" value="toggle_archived">
|
|
<button
|
|
type="submit"
|
|
class="px-4 py-2 rounded-md font-medium border <?php echo $critter['isArchived'] ? 'bg-gray-800 border-gray-800 text-white hover:bg-gray-700' : 'bg-white border-gray-300 text-gray-800 hover:bg-gray-100'; ?>"
|
|
>
|
|
<?php echo $critter['isArchived'] ? 'Unarchive' : 'Archive'; ?>
|
|
</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
<form action="create-critter.php" method="get">
|
|
<input type="hidden" name="adjective_id" value="<?php echo (int) $critter['adjective_id']; ?>">
|
|
<input type="hidden" name="noun_id" value="<?php echo (int) $critter['noun_id']; ?>">
|
|
<input type="hidden" name="verb_id" value="<?php echo (int) $critter['verb_id']; ?>">
|
|
<input type="hidden" name="location_id" value="<?php echo (int) $critter['location_id']; ?>">
|
|
<button type="submit" class="px-4 py-2 rounded-md font-medium border bg-white border-gray-300 text-gray-800 hover:bg-gray-100">
|
|
Remix
|
|
</button>
|
|
</form>
|
|
</div>
|
|
<div class="mt-8 pt-6 border-t border-gray-200 text-center">
|
|
<h2 class="text-sm font-semibold text-gray-500 uppercase tracking-wide mb-3">Quick Filters</h2>
|
|
<ul class="space-y-2">
|
|
<li>
|
|
<a href="/?filter_noun=<?php echo (int) $critter['noun_id']; ?>" class="hover:underline">
|
|
Show me all my <?php echo htmlspecialchars($critter['noun'], ENT_QUOTES, 'UTF-8'); ?> critters
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/?filter_adjective=<?php echo (int) $critter['adjective_id']; ?>" class="hover:underline">
|
|
Show me all my <?php echo htmlspecialchars($critter['adjective'], ENT_QUOTES, 'UTF-8'); ?> critters
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/?filter_verb=<?php echo (int) $critter['verb_id']; ?>" class="hover:underline">
|
|
Show me any critter that I've created that <?php echo htmlspecialchars($critter['verb'], ENT_QUOTES, 'UTF-8'); ?>
|
|
</a>
|
|
</li>
|
|
<li>
|
|
<a href="/?filter_location=<?php echo (int) $critter['location_id']; ?>" class="hover:underline">
|
|
Show me all my critters <?php echo htmlspecialchars($critter['location'], ENT_QUOTES, 'UTF-8'); ?>
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<?php if (!empty($relatedCritters)): ?>
|
|
<div class="mt-8 pt-6 border-t border-gray-200 text-center">
|
|
<h2 class="text-sm font-semibold text-gray-500 uppercase tracking-wide mb-3">Other critters with this same recipe</h2>
|
|
<div class="grid grid-cols-4 gap-2">
|
|
<?php foreach ($relatedCritters as $related): ?>
|
|
<a href="single-critter.php?id=<?php echo (int) $related['id']; ?>">
|
|
<img
|
|
src="critter-images/<?php echo htmlspecialchars($related['image'], ENT_QUOTES, 'UTF-8'); ?>"
|
|
alt="AI-generated image of a matching critter"
|
|
class="w-full aspect-square object-cover rounded-lg border border-gray-200 shadow-sm"
|
|
>
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php else: ?>
|
|
<p>Critter not found.</p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php require __DIR__ . '/lib/footer.php'; ?>
|
|
</body>
|
|
</html>
|