<?php
if (!isLoggedIn()) {
header('Location: ' . url('signin'));
exit;
}
$pageTitle = "Contribute – Seven O'Clock Dinner Club";
$errors = [];
$successMessage = null;
if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') {
//var_dump($_FILES['image']);
//exit;
if (!empty($errors)) {
var_dump($file['size'], $errors);
exit;
}
$quote = trim($_POST['quote'] ?? '');
$attribution = trim($_POST['attribution'] ?? '');
$userId = currentUserId();
if ($quote === '') {
$errors[] = 'Please add a quote.';
}
if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
$errors[] = 'Please attach a picture.';
} else {
$file = $_FILES['image'];
if ($file['size'] > 20 * 1024 * 1024) {
$errors[] = 'Images are limited to 20MB.';
}
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
// Allow common photo formats including Apple HEIC/HEIF
$allowedMimes = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/heic' => 'heic',
'image/heif' => 'heic',
'image/heic-sequence' => 'heic',
'image/heif-sequence' => 'heic',
];
if (!array_key_exists($mime, $allowedMimes)) {
$errors[] = 'Please upload a JPEG, PNG, or HEIC file.';
}
}
if (!$errors) {
// Choose the file extension based on MIME type
$allowedMimes = [
'image/jpeg' => 'jpg',
'image/png' => 'png',
'image/heic' => 'heic',
'image/heif' => 'heic',
'image/heic-sequence' => 'heic',
'image/heif-sequence' => 'heic',
];
$ext = $allowedMimes[$mime] ?? 'jpg';
// Store uploads in a web-accessible /uploads directory at the app root
$uploadsDir = __DIR__ . '/../../uploads';
if (!is_dir($uploadsDir)) {
mkdir($uploadsDir, 0775, true);
}
$basename = bin2hex(random_bytes(12)) . '.' . $ext;
$target = $uploadsDir . '/' . $basename;
if (!move_uploaded_file($file['tmp_name'], $target)) {
$errors[] = 'We were unable to save the image.';
} else {
$publicPath = url('uploads/' . $basename);
// Automatically visible on the site; admins can still remove uploads from the dashboard
$nowStr = (new DateTimeImmutable('now'))->format('Y-m-d H:i:s');
$stmt = $db->prepare('INSERT INTO uploads (user_id, image_url, quote_text, attribution, is_approved, created_at) VALUES (?, ?, ?, ?, 1, ?)');
$stmt->bind_param('issss', $userId, $publicPath, $quote, $attribution, $nowStr);
$stmt->execute();
// After a successful upload, redirect to the main page and jump to the new post.
$newUploadId = (int)$db->insert_id;
header('Location: ' . url('/') . '?highlight_upload=' . $newUploadId . '#upload-' . $newUploadId);
exit;
}
}
}
$userId = currentUserId();
$stmt = $db->prepare('
SELECT
u.id,
u.image_url,
u.quote_text,
u.attribution,
u.is_approved,
u.created_at,
m.display_name,
(SELECT COUNT(*) FROM upload_reactions r WHERE r.upload_id = u.id AND r.reaction = "like") AS like_count,
(SELECT COUNT(*) FROM upload_reactions r WHERE r.upload_id = u.id AND r.reaction = "dislike") AS dislike_count,
(SELECT COUNT(*) FROM upload_comments c WHERE c.upload_id = u.id) AS comment_count,
0 AS my_reaction_unused
FROM uploads u
LEFT JOIN member_profiles m ON m.user_id = u.user_id
WHERE u.user_id = ?
ORDER BY u.created_at DESC
LIMIT 12
');
$uid = currentUserId();
$stmt->bind_param('i', $userId);
$stmt->execute();
$myUploads = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
?>
<section class="page-grid">
<div class="card" data-animate-initial>
<div class="muted" style="font-size: 11px; letter-spacing: 0.18em; text-transform: uppercase; margin-bottom: 10px;">
Contribute
</div>
<h1 style="font-family: 'Georgia', 'Times New Roman', serif; font-weight: 400; font-size: 26px; margin: 0 0 12px;">
Share a moment from dinner.
</h1>
<?php if ($errors): ?>
<ul style="margin-top: 12px; padding-left: 18px; color: #9b2c2c; font-size: 13px;">
<?php foreach ($errors as $err): ?>
<li><?= htmlspecialchars($err, ENT_QUOTES, 'UTF-8') ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<?php if ($successMessage): ?>
<p style="margin-top: 12px; font-size: 13px; color: #22543d;">
<?= htmlspecialchars($successMessage, ENT_QUOTES, 'UTF-8') ?>
</p>
<?php endif; ?>
</div>
<div class="card" data-animate>
<form method="post" enctype="multipart/form-data" style="display: grid; gap: 10px; font-size: 13px; margin-bottom: 0;">
<label>
Photograph<br>
<input type="file" name="image" accept="image/jpeg,image/png" required style="width: 100%; padding: 6px 0;">
</label>
<label>
Quote<br>
<textarea name="quote" rows="3" required style="width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid rgba(0,0,0,0.12); background: rgba(255,255,255,0.8);"></textarea>
</label>
<label>
Attribution (optional)<br>
<input name="attribution" type="text" placeholder="Guest name, occasion, etc." style="width: 100%; padding: 8px 10px; border-radius: 8px; border: 1px solid rgba(0,0,0,0.12); background: rgba(255,255,255,0.8);">
</label>
<button type="submit" class="pill pill-accent" style="margin-top: 6px; justify-content: center;">
Submit
</button>
</form>
</div>
<?php if ($myUploads): ?>
<div class="card" data-animate>
<div class="muted" style="font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase; margin-bottom: 8px;">
Your contributions
</div>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px;">
<?php foreach ($myUploads as $upload): ?>
<?php $posterName = $upload['display_name'] ?? 'You'; ?>
<figure style="margin: 0; border-radius: 12px; overflow: hidden; border: 1px solid rgba(0,0,0,0.08); background: var(--bg-elevated);">
<button type="button" data-image-full="<?= htmlspecialchars($upload['image_url'], ENT_QUOTES, 'UTF-8') ?>" style="all: unset; display: block; width: 100%; cursor: zoom-in;">
<img src="<?= htmlspecialchars($upload['image_url'], ENT_QUOTES, 'UTF-8') ?>" alt="" style="display:block; width:100%; height:auto; aspect-ratio:4 / 5; object-fit:cover; object-position:center center; filter:grayscale(30%); border-radius: 12px 12px 0 0;">
</button>
<figcaption style="padding: 10px 12px 12px; background: #ffffff; font-size: 12px; line-height: 1.5;">
<div style="font-size: 13px; margin-bottom: 4px;">
“<?= htmlspecialchars($upload['quote_text'], ENT_QUOTES, 'UTF-8') ?>”
</div>
<?php if (!empty($upload['attribution'])): ?>
<div class="muted" style="font-size: 12px; margin-bottom: 4px;">
<?= htmlspecialchars($upload['attribution'], ENT_QUOTES, 'UTF-8') ?>
</div>
<?php endif; ?>
<div style="display: flex; justify-content: space-between; align-items: center; font-size: 11px; margin-top: 6px;">
<span class="muted">
<?= $upload['is_approved'] ? 'Approved' : 'Pending' ?>
</span>
<span style="opacity: 0.7;">
<?= htmlspecialchars(date('M j', strtotime($upload['created_at'])), ENT_QUOTES, 'UTF-8') ?>
</span>
</div>
<div class="muted" style="margin-top: 6px; font-size: 11px;">
Uploaded by <?= htmlspecialchars($posterName, ENT_QUOTES, 'UTF-8') ?>
</div>
<div style="margin-top: 10px; display:flex; gap: 8px; flex-wrap: nowrap; align-items:center; justify-content: space-between; width: 100%;">
<div style="display:flex; gap: 8px; align-items:center;">
<button
type="button"
class="pill"
style="font-size: 12px; padding: 6px 12px;"
aria-label="Upvote"
data-open-upload-interactions
data-upload-id="<?= htmlspecialchars((string)($upload['id'] ?? ''), ENT_QUOTES, 'UTF-8') ?>"
data-reaction="like"
>
▲ <?= (int)($upload['like_count'] ?? 0) ?>
</button>
<button
type="button"
class="pill"
style="font-size: 12px; padding: 6px 12px;"
aria-label="Downvote"
data-open-upload-interactions
data-upload-id="<?= htmlspecialchars((string)($upload['id'] ?? ''), ENT_QUOTES, 'UTF-8') ?>"
data-reaction="dislike"
>
▼ <?= (int)($upload['dislike_count'] ?? 0) ?>
</button>
</div>
<button
type="button"
class="pill"
style="font-size: 11px; padding: 6px 12px;"
data-open-upload-interactions
data-upload-id="<?= htmlspecialchars((string)($upload['id'] ?? ''), ENT_QUOTES, 'UTF-8') ?>"
data-open-comments="1"
>
Comments (<?= (int)($upload['comment_count'] ?? 0) ?>)
</button>
</div>
</figcaption>
</figure>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</section>