Journal renders correctly
This commit is contained in:
@@ -4,6 +4,22 @@ namespace MyPrayerJournal;
|
||||
|
||||
class Layout
|
||||
{
|
||||
/**
|
||||
* Generate the heading for a bare result
|
||||
*/
|
||||
public static function bareHead(): void
|
||||
{
|
||||
echo '<!DOCTYPE html><html lang=en><head><title></title></head><body>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the end of a bare result
|
||||
*/
|
||||
public static function bareFoot(): void
|
||||
{
|
||||
echo '</body></html>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the `DOCTYPE` declaration, `html`, and `head` tags for the page
|
||||
*
|
||||
@@ -38,7 +54,7 @@ class Layout
|
||||
default => []
|
||||
};
|
||||
echo '<li class=nav-item>';
|
||||
page_link($url, $text, $classAttr);
|
||||
UI::pageLink($url, $text, $classAttr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,7 +64,7 @@ class Layout
|
||||
{ ?>
|
||||
<nav class="navbar navbar-dark" role="navigation">
|
||||
<div class=container-fluid><?php
|
||||
page_link('/', '<span class=m>my</span><span class=p>Prayer</span><span class=j>Journal</span>',
|
||||
UI::pageLink('/', '<span class=m>my</span><span class=p>Prayer</span><span class=j>Journal</span>',
|
||||
['class' => 'navbar-brand']); ?>
|
||||
<ul class="navbar-nav me-auto d-flex flex-row"><?php
|
||||
if (key_exists('user_id', $_SESSION)) {
|
||||
@@ -91,9 +107,9 @@ class Layout
|
||||
<p class="text-muted text-end">
|
||||
myPrayerJournal <?=self::displayVersion();?><br>
|
||||
<em><small><?php
|
||||
page_link('/legal/privacy-policy', 'Privacy Policy');
|
||||
UI::pageLink('/legal/privacy-policy', 'Privacy Policy');
|
||||
echo ' • ';
|
||||
page_link('/legal/terms-of-service', 'Terms of Service');
|
||||
UI::pageLink('/legal/terms-of-service', 'Terms of Service');
|
||||
echo ' • '; ?>
|
||||
<a href=https://git.bitbadger.solutions/bit-badger/myPrayerJournal target=_blank
|
||||
rel=noopener>Developed</a> and hosted by
|
||||
@@ -114,15 +130,4 @@ class Layout
|
||||
</footer><?php
|
||||
}
|
||||
|
||||
/// Create a card when there are no results found
|
||||
public static function noResults(string $heading, string $link, string $buttonText, string $text): void
|
||||
{ ?>
|
||||
<div class=card>
|
||||
<h5 class=card-header><?=$heading?></h5>
|
||||
<div class="card-body text-center">
|
||||
<p class=card-text><?=$text?></p><?php
|
||||
page_link($link, $buttonText, ['class' => 'btn btn-primary']); ?>
|
||||
</div>
|
||||
</div><?php
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
namespace MyPrayerJournal;
|
||||
|
||||
use BitBadger\PDODocument\{DocumentException, Find};
|
||||
use DateTimeImmutable;
|
||||
use BitBadger\PDODocument\{Custom, DocumentException, DocumentList, Find, Mapper\DocumentMapper};
|
||||
use Exception;
|
||||
use JsonSerializable;
|
||||
use Visus\Cuid2\Cuid2;
|
||||
@@ -34,16 +35,25 @@ class Request implements JsonSerializable
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a request by its ID
|
||||
* Get the current text for this request
|
||||
*
|
||||
* @param string $id The ID of the request
|
||||
* @return Request|false The request if it is found and belongs to the current user, false if not
|
||||
* @throws DocumentException If any is encountered
|
||||
* @return string The most recent text for the request
|
||||
*/
|
||||
public static function byId(string $id): Request|false
|
||||
public function currentText(): string
|
||||
{
|
||||
$req = Find::byId(Table::REQUEST, $id, self::class);
|
||||
return ($req && $req->userId == $_SESSION['user_id']) ? $req : false;
|
||||
foreach ($this->history as $hist) if (isset($hist->text)) return $hist->text;
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date/time this request was last marked as prayed
|
||||
*
|
||||
* @return string|null The date/time this request was last marked as prayed
|
||||
*/
|
||||
public function lastPrayed(): ?string
|
||||
{
|
||||
foreach ($this->history as $hist) if ($hist->action == RequestAction::Prayed) return $hist->asOf;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): mixed
|
||||
@@ -60,4 +70,41 @@ class Request implements JsonSerializable
|
||||
if (!is_null($this->showAfter)) $values['showAfter'] = $this->showAfter;
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a request by its ID
|
||||
*
|
||||
* @param string $id The ID of the request
|
||||
* @return Request|false The request if it is found and belongs to the current user, false if not
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function byId(string $id): Request|false
|
||||
{
|
||||
$req = Find::byId(Table::REQUEST, $id, self::class);
|
||||
return ($req && $req->userId == $_SESSION['user_id']) ? $req : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user's active journal requests
|
||||
*
|
||||
* @return DocumentList<Request> The requests for the user's journal
|
||||
* @throws DocumentException If any is encountered
|
||||
*/
|
||||
public static function forJournal(): DocumentList
|
||||
{
|
||||
$table = Table::REQUEST;
|
||||
return Custom::list(<<<SQL
|
||||
SELECT data, (
|
||||
SELECT h.value->>'asOf' as_of
|
||||
FROM $table i LEFT JOIN json_each(i.data, '$.history') h
|
||||
WHERE r.data->>'id' = i.data->>'id' AND h.value->>'action' = 'Prayed'
|
||||
LIMIT 1) last_prayed
|
||||
FROM $table r
|
||||
WHERE data->>'userId' = :userId
|
||||
AND data->>'$.history[0].action' <> 'Answered'
|
||||
AND (data->>'snoozedUntil' IS NULL OR data->>'snoozedUntil' < datetime('now'))
|
||||
AND (data->>'showAfter' IS NULL OR data->>'showAfter' < datetime('now'))
|
||||
ORDER BY coalesce(last_prayed, data->>'snoozedUntil', data->>'showAfter', data->>'$.history[0].asOf')
|
||||
SQL, [':userId' => $_SESSION['user_id']], new DocumentMapper(self::class));
|
||||
}
|
||||
}
|
||||
|
||||
79
src/lib/UI.php
Normal file
79
src/lib/UI.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace MyPrayerJournal;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* User interface building blocks
|
||||
*/
|
||||
class UI
|
||||
{
|
||||
/**
|
||||
* Generate a material icon
|
||||
*
|
||||
* @param string $name The name of the material icon
|
||||
* @return string The material icon wrapped in a `span` tag
|
||||
*/
|
||||
public static function icon(string $name): string {
|
||||
return "<span class=material-icons>$name</span>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a card when there are no results found
|
||||
*/
|
||||
public static function noResults(string $heading, string $link, string $buttonText, string $text): void
|
||||
{ ?>
|
||||
<div class=card>
|
||||
<h5 class=card-header><?=$heading?></h5>
|
||||
<div class="card-body text-center">
|
||||
<p class=card-text><?=$text?></p><?php
|
||||
self::pageLink($link, $buttonText, ['class' => 'btn btn-primary']); ?>
|
||||
</div>
|
||||
</div><?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a link to a page within myPrayerJournal
|
||||
*
|
||||
* @param string $href The URL for the link
|
||||
* @param string $text The text for the link
|
||||
* @param array $attrs Any additional attributes that should be placed on the `a` tag
|
||||
*/
|
||||
public static function pageLink(string $href, string $text, array $attrs = []): void
|
||||
{ ?>
|
||||
<a href="<?=$href?>" hx-get="<?=$href?>" hx-target=#top hx-swap=innerHTML hx-push-url=true<?php
|
||||
foreach ($attrs as $key => $value) echo " $key=\"" . htmlspecialchars($value) . "\""; ?>><?=$text?></a><?php
|
||||
}
|
||||
|
||||
// Thanks, William Entriken! https://stackoverflow.com/a/42446994/276707
|
||||
/** @var array Periods for the relative date/time display */
|
||||
private static array $periods = [
|
||||
[ 60, 1, '%s seconds ago', 'a second ago'],
|
||||
[ 60*100, 60, '%s minutes ago', 'one minute ago'],
|
||||
[ 3600*70, 3600, '%s hours ago', 'an hour ago'],
|
||||
[ 3600*24*10, 3600*24, '%s days ago', 'yesterday'],
|
||||
[ 3600*24*30, 3600*24*7, '%s weeks ago', 'a week ago'],
|
||||
[3600*24*30*30, 3600*24*30, '%s months ago', 'last month'],
|
||||
[ INF, 3600*24*265, '%s years ago', 'last year']
|
||||
];
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function relativeDate(string $date): void
|
||||
{
|
||||
$parsed = new DateTimeImmutable($date);
|
||||
$diff = time() - $parsed->getTimestamp();
|
||||
foreach (self::$periods as $period) {
|
||||
if ($diff > $period[0]) continue;
|
||||
$diff = floor($diff / $period[1]);
|
||||
$value = $diff > 1 ? sprintf($period[2], $diff) : $period[3];
|
||||
$inZone = $parsed->setTimezone(new DateTimeZone($_SERVER['HTTP_X_TIME_ZONE'] ?? 'Etc/UTC'));
|
||||
echo '<span title="' . date_format($inZone, 'l, F j, Y \a\t g:ia T') . '">' . $value . '</span>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user