Add flash messages.
This commit is contained in:
parent
0b4348f14b
commit
856677659e
@ -38,6 +38,23 @@
|
||||
/* Shadow colors */
|
||||
--shadow-primary: rgba(66, 153, 225, 0.1);
|
||||
--shadow-primary-strong: rgba(66, 153, 225, 0.3);
|
||||
|
||||
/* Flash colors */
|
||||
--color-flash-success: #155724;
|
||||
--color-flash-success-bg: #d4edda;
|
||||
--color-flash-success-border-left: #28a745;
|
||||
|
||||
--color-flash-error: #721c24;
|
||||
--color-flash-error-bg: #f8d7da;
|
||||
--color-flash-error-border-left: #dc3545;
|
||||
|
||||
--color-flash-warning: #856404;
|
||||
--color-flash-warning-bg: #fff3cd;
|
||||
--color-flash-warning-border-left: #ffc107;
|
||||
|
||||
--color-flash-info: #0c5460;
|
||||
--color-flash-info-bg: #d1ecf1;
|
||||
--color-flash-info-border-left: #17a2b8;
|
||||
}
|
||||
|
||||
body {
|
||||
@ -227,6 +244,46 @@ label.description {
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.flash-messages {
|
||||
background: white;
|
||||
margin-top: 10px;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.flash-message {
|
||||
padding: 12px 16px;
|
||||
margin: 5px 0;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.flash-success {
|
||||
background-color: var(--color-flash-success-bg);
|
||||
border-left-color: var(--color-flash-success-border-left);
|
||||
color: var(--color-flash-success);
|
||||
}
|
||||
|
||||
.flash-error {
|
||||
background-color: var(--color-flash-error-bg);
|
||||
border-left-color: var(--color-flash-error-border-left);
|
||||
color: var(--color-flash-error);
|
||||
}
|
||||
|
||||
.flash-warning {
|
||||
background-color: var(--color-flash-warning-bg);
|
||||
border-left-color: var(--color-flash-warning-border-left);
|
||||
color: var(--color-flash-warning);
|
||||
}
|
||||
|
||||
.flash-info {
|
||||
background-color: var(--color-flash-info-bg);
|
||||
border-left-color: var(--color-flash-info-border-left);
|
||||
color: var(--color-flash-info);
|
||||
}
|
||||
|
||||
.fieldset-items {
|
||||
margin-bottom: 14px;
|
||||
display: grid;
|
||||
|
@ -100,11 +100,11 @@ class AdminController extends Controller {
|
||||
}
|
||||
|
||||
// If a password was sent, make sure it matches the confirmation
|
||||
if ($password && !($password = $confirmPassword)){
|
||||
if ($password && !($password === $confirmPassword)){
|
||||
$errors[] = "Passwords do not match";
|
||||
}
|
||||
|
||||
// TODO: Actually handle errors
|
||||
// Validation complete
|
||||
if (empty($errors)) {
|
||||
// Update site settings
|
||||
$config->siteTitle = $siteTitle;
|
||||
@ -114,6 +114,7 @@ class AdminController extends Controller {
|
||||
$config->itemsPerPage = $itemsPerPage;
|
||||
|
||||
// Save site settings and reload config from database
|
||||
// TODO - raise and handle exception on failure
|
||||
$config = $config->save();
|
||||
|
||||
// Update user profile
|
||||
@ -123,19 +124,24 @@ class AdminController extends Controller {
|
||||
$user->website = $website;
|
||||
|
||||
// Save user profile and reload user from database
|
||||
// TODO - raise and handle exception on failure
|
||||
$user = $user->save();
|
||||
|
||||
// Update the password if one was sent
|
||||
// TODO - raise and handle exception on failure
|
||||
if($password){
|
||||
$user->set_password($password);
|
||||
}
|
||||
|
||||
Session::setFlashMessage('success', 'Settings updated');
|
||||
} else {
|
||||
echo implode(",", $errors);
|
||||
exit;
|
||||
foreach($errors as $error){
|
||||
Session::setFlashMessage('error', $error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: ' . $config->basePath . 'admin');
|
||||
header('Location: ' . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,15 @@ class Controller {
|
||||
throw new RuntimeException("Template not found: $childTemplatePath");
|
||||
}
|
||||
|
||||
// always check for flash messages and add them if they exist
|
||||
if (Session::hasFlashMessages()){
|
||||
$flashMessages = Session::getFlashMessages();
|
||||
$flashView = new FlashView();
|
||||
$flashSection = $flashView->renderFlashSection($flashMessages);
|
||||
|
||||
$vars['flashSection'] = $flashSection;
|
||||
}
|
||||
|
||||
extract($vars, EXTR_SKIP);
|
||||
include $templatePath;
|
||||
}
|
||||
|
@ -63,7 +63,8 @@ class CssController extends Controller {
|
||||
break;
|
||||
}
|
||||
|
||||
header('Location: ' . $config->basePath . 'admin/css');
|
||||
// redirect after handling to avoid resubmitting form
|
||||
header('Location: ' . $_SERVER['PHP_SELF']);
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -114,6 +115,9 @@ class CssController extends Controller {
|
||||
// Set the theme back to default
|
||||
$config->cssId = null;
|
||||
$config = $config->save();
|
||||
|
||||
// Set flash message
|
||||
Session::setFlashMessage('success', 'Theme ' . $cssFilename . ' deleted.');
|
||||
}
|
||||
|
||||
private function handleSetTheme() {
|
||||
@ -129,6 +133,9 @@ class CssController extends Controller {
|
||||
|
||||
// Update the site theme
|
||||
$config = $config->save();
|
||||
|
||||
// Set flash message
|
||||
Session::setFlashMessage('success', 'Theme applied.');
|
||||
}
|
||||
|
||||
private function handleUpload() {
|
||||
@ -179,11 +186,14 @@ class CssController extends Controller {
|
||||
// Add upload to database
|
||||
$cssModel = new CssModel();
|
||||
$cssModel->save($safeFilename, $description);
|
||||
|
||||
return true;
|
||||
|
||||
// Set success flash message
|
||||
Session::setFlashMessage('success', 'Theme uploaded as ' . $safeFilename);
|
||||
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
// Set error flash message
|
||||
// Todo - don't do a global catch like this. Subclass Exception.
|
||||
Session::setFlashMessage('error', 'Upload exception: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,30 @@ class Session {
|
||||
return self::isLoggedIn() && self::isValidCsrfToken($token);
|
||||
}
|
||||
|
||||
// valid types are:
|
||||
// - success
|
||||
// - error
|
||||
// - info
|
||||
// - warning
|
||||
public static function setFlashMessage(string $type, string $message): void {
|
||||
if (!isset($_SESSION['flash'][$type])){
|
||||
$_SESSION['flash'][$type] = [];
|
||||
}
|
||||
$_SESSION['flash'][$type][] = $message;
|
||||
}
|
||||
|
||||
public static function getFlashMessages(): ?array {
|
||||
if (isset($_SESSION['flash'])) {
|
||||
$messages = $_SESSION['flash'];
|
||||
unset($_SESSION['flash']);
|
||||
return $messages;
|
||||
}
|
||||
}
|
||||
|
||||
public static function hasFlashMessages(): bool {
|
||||
return isset($_SESSION['flash']) && !empty($_SESSION['flash']);
|
||||
}
|
||||
|
||||
public static function end(): void {
|
||||
$_SESSION = [];
|
||||
session_destroy();
|
||||
|
21
src/View/FlashView/FlashView.php
Normal file
21
src/View/FlashView/FlashView.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
class FlashView {
|
||||
public function renderFlashSection(array $flashMessages): string {
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
<?php if (count($flashMessages) > 0): ?>
|
||||
<div class="flash-messages">
|
||||
<?php foreach ($flashMessages as $type => $messages): ?>
|
||||
<?php foreach ($messages as $message): ?>
|
||||
<div class="flash-message flash-<?php echo $type; ?>">
|
||||
<?php echo htmlspecialchars($message); ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif;
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
<?php /** @var ConfigModel $config */ ?>
|
||||
<?php /** @var UserModel $user */ ?>
|
||||
<?php /** @var string $childTemplateFile */ ?>
|
||||
<?php /** @var srting $flashSection */ ?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@ -25,6 +26,9 @@
|
||||
</head>
|
||||
<body>
|
||||
<?php include TEMPLATES_DIR . '/partials/navbar.php'?>
|
||||
<?php if( isset($flashSection) && !empty($flashSection) ): ?>
|
||||
<?php echo $flashSection; ?>
|
||||
<?php endif; ?>
|
||||
<?php include TEMPLATES_DIR . '/partials/' . $childTemplateFile?>
|
||||
</body>
|
||||
</html>
|
@ -8,7 +8,7 @@
|
||||
method="post">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
|
||||
<fieldset>
|
||||
<legend>UserModel settings</legend>
|
||||
<legend>User settings</legend>
|
||||
<div class="fieldset-items">
|
||||
<label>Username <span class=required>*</span></label>
|
||||
<input type="text"
|
||||
@ -16,10 +16,10 @@
|
||||
value="<?= $user->username ?>"
|
||||
required>
|
||||
<label>Display name <span class=required>*</span></label>
|
||||
<input type="text"
|
||||
name="display_name"
|
||||
value="<?= $user->displayName ?>"
|
||||
required>
|
||||
<input type="text"
|
||||
name="display_name"
|
||||
value="<?= $user->displayName ?>"
|
||||
required>
|
||||
<label>About </label>
|
||||
<input type="text"
|
||||
name="about"
|
||||
|
@ -18,7 +18,9 @@
|
||||
maxlength="40" minlength="1"
|
||||
placeholder="describe the mood"
|
||||
>
|
||||
<div></div>
|
||||
<button type="submit" name="action" value="add">Add emoji</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
<?php if (!empty($emojiList)): ?>
|
||||
|
@ -6,8 +6,13 @@
|
||||
<p style="color:red"><?= htmlspecialchars($error) ?></p>
|
||||
<?php endif; ?>
|
||||
<form method="post" action="<?= $config->basePath ?>login">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf_token) ?>">
|
||||
<label>Username: <input type="text" name="username" required></label><br>
|
||||
<label>Password: <input type="password" name="password" required></label><br>
|
||||
<button type="submit" class="submit-btn">Login</button>
|
||||
<div class="fieldset-items">
|
||||
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($csrf_token) ?>">
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" required></label>
|
||||
<div></div>
|
||||
<button type="submit" class="submit-btn">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
|
Loading…
x
Reference in New Issue
Block a user