Adapt relative date logic from F# version
This commit is contained in:
parent
b759c3494e
commit
3ebb03d470
@ -526,45 +526,45 @@ let routes = [
|
|||||||
GET_HEAD [ route "/" Home.home ]
|
GET_HEAD [ route "/" Home.home ]
|
||||||
subRoute "/components/" [
|
subRoute "/components/" [
|
||||||
GET_HEAD [
|
GET_HEAD [
|
||||||
route "journal-items" Components.journalItems
|
route "journal-items" Components.journalItems // done
|
||||||
routef "request/%s/add-notes" Components.addNotes
|
routef "request/%s/add-notes" Components.addNotes
|
||||||
routef "request/%s/item" Components.requestItem
|
routef "request/%s/item" Components.requestItem
|
||||||
routef "request/%s/notes" Components.notes
|
routef "request/%s/notes" Components.notes
|
||||||
routef "request/%s/snooze" Components.snooze
|
routef "request/%s/snooze" Components.snooze
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
GET_HEAD [ route "/docs" Home.docs ]
|
GET_HEAD [ route "/docs" Home.docs ] // done
|
||||||
GET_HEAD [ route "/journal" Journal.journal ]
|
GET_HEAD [ route "/journal" Journal.journal ] // done
|
||||||
subRoute "/legal/" [
|
subRoute "/legal/" [
|
||||||
GET_HEAD [
|
GET_HEAD [
|
||||||
route "privacy-policy" Legal.privacyPolicy
|
route "privacy-policy" Legal.privacyPolicy // done
|
||||||
route "terms-of-service" Legal.termsOfService
|
route "terms-of-service" Legal.termsOfService // done
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
subRoute "/request" [
|
subRoute "/request" [
|
||||||
GET_HEAD [
|
GET_HEAD [
|
||||||
routef "/%s/edit" Request.edit
|
routef "/%s/edit" Request.edit // done
|
||||||
routef "/%s/full" Request.getFull
|
routef "/%s/full" Request.getFull // done
|
||||||
route "s/active" Request.active
|
route "s/active" Request.active // done
|
||||||
route "s/answered" Request.answered
|
route "s/answered" Request.answered // done
|
||||||
route "s/snoozed" Request.snoozed
|
route "s/snoozed" Request.snoozed
|
||||||
]
|
]
|
||||||
PATCH [
|
PATCH [
|
||||||
route "" Request.update
|
route "" Request.update // done
|
||||||
routef "/%s/cancel-snooze" Request.cancelSnooze
|
routef "/%s/cancel-snooze" Request.cancelSnooze
|
||||||
routef "/%s/prayed" Request.prayed
|
routef "/%s/prayed" Request.prayed // done
|
||||||
routef "/%s/show" Request.show
|
routef "/%s/show" Request.show
|
||||||
routef "/%s/snooze" Request.snooze
|
routef "/%s/snooze" Request.snooze
|
||||||
]
|
]
|
||||||
POST [
|
POST [
|
||||||
route "" Request.add
|
route "" Request.add // done
|
||||||
routef "/%s/note" Request.addNote
|
routef "/%s/note" Request.addNote
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
subRoute "/user/" [
|
subRoute "/user/" [
|
||||||
GET_HEAD [
|
GET_HEAD [
|
||||||
route "log-off" User.logOff
|
route "log-off" User.logOff // done
|
||||||
route "log-on" User.logOn
|
route "log-on" User.logOn // done
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace MyPrayerJournal;
|
namespace MyPrayerJournal;
|
||||||
|
|
||||||
use DateTimeImmutable;
|
|
||||||
use BitBadger\PDODocument\{Custom, DocumentException, DocumentList, Find, Mapper\DocumentMapper};
|
use BitBadger\PDODocument\{Custom, DocumentException, DocumentList, Find, Mapper\DocumentMapper};
|
||||||
use Exception;
|
use Exception;
|
||||||
use JsonSerializable;
|
use JsonSerializable;
|
||||||
|
@ -6,6 +6,7 @@ use BitBadger\PDODocument\DocumentException;
|
|||||||
use BitBadger\PDODocument\DocumentList;
|
use BitBadger\PDODocument\DocumentList;
|
||||||
use DateTimeImmutable;
|
use DateTimeImmutable;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User interface building blocks
|
* User interface building blocks
|
||||||
@ -103,33 +104,69 @@ class UI
|
|||||||
foreach ($attrs as $key => $value) echo " $key=\"" . htmlspecialchars($value) . "\""; ?>><?=$text?></a><?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
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function relativeDate(string $date): void
|
public static function relativeDate(string $date): void
|
||||||
{
|
{
|
||||||
$parsed = new DateTimeImmutable($date);
|
$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'));
|
$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>';
|
echo '<span title="' . date_format($inZone, 'l, F j, Y \a\t g:ia T') . '">'
|
||||||
break;
|
. self::formatDistance('now', $parsed) . '</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Many thanks to date-fns (https://date-fns.org) for this logic
|
||||||
|
/**
|
||||||
|
* Format the distance between two dates
|
||||||
|
*
|
||||||
|
* @param string|DateTimeImmutable $from The starting date/time
|
||||||
|
* @param string|DateTimeImmutable $to The ending date/time
|
||||||
|
* @return string The distance between two dates
|
||||||
|
* @throws Exception If date/time objects cannot be created
|
||||||
|
*/
|
||||||
|
public static function formatDistance(string|DateTimeImmutable $from, string|DateTimeImmutable $to): string
|
||||||
|
{
|
||||||
|
$aDay = 1_440.0;
|
||||||
|
$almost2Days = 2_520.0;
|
||||||
|
$aMonth = 43_200.0;
|
||||||
|
$twoMonths = 86_400.0;
|
||||||
|
|
||||||
|
$dtFrom = is_string($from) ? new DateTimeImmutable($from) : $from;
|
||||||
|
$dtTo = is_string($to) ? new DateTimeImmutable($to) : $to;
|
||||||
|
$minutes = abs($dtFrom->getTimestamp() - $dtTo->getTimestamp()) / 60;
|
||||||
|
$months = round($minutes / $aMonth);
|
||||||
|
$years = round($months / 12);
|
||||||
|
|
||||||
|
$typeAndNumber = match (true) {
|
||||||
|
$minutes < 1.0 => [FormatDistanceToken::LessThanXMinutes, 1],
|
||||||
|
$minutes < 45.0 => [FormatDistanceToken::XMinutes, round($minutes)],
|
||||||
|
$minutes < 90.0 => [FormatDistanceToken::AboutXHours, 1],
|
||||||
|
$minutes < $aDay => [FormatDistanceToken::AboutXHours, round($minutes / 60)],
|
||||||
|
$minutes < $almost2Days => [FormatDistanceToken::XDays, 1],
|
||||||
|
$minutes < $aMonth => [FormatDistanceToken::XDays, round($minutes / $aDay)],
|
||||||
|
$minutes < $twoMonths => [FormatDistanceToken::AboutXMonths, round($minutes / $aMonth)],
|
||||||
|
$months < 12 => [FormatDistanceToken::XMonths, round($minutes / $aMonth)],
|
||||||
|
$months % 12 < 3 => [FormatDistanceToken::AboutXYears, $years],
|
||||||
|
$months % 12 < 9 => [FormatDistanceToken::OverXYears, $years],
|
||||||
|
default => [FormatDistanceToken::AlmostXYears, $years]
|
||||||
|
};
|
||||||
|
$format = match ($typeAndNumber[0]) {
|
||||||
|
FormatDistanceToken::LessThanXMinutes => ['less than a minute', 'less than %d minutes'],
|
||||||
|
FormatDistanceToken::XMinutes => ['a minute', '%d minutes'],
|
||||||
|
FormatDistanceToken::AboutXHours => ['about an hour', 'about %d hours'],
|
||||||
|
FormatDistanceToken::XHours => ['an hour', '%d hours'],
|
||||||
|
FormatDistanceToken::XDays => ['a day', '%d days'],
|
||||||
|
FormatDistanceToken::AboutXWeeks => ['about a week', 'about %d weeks'],
|
||||||
|
FormatDistanceToken::XWeeks => ['a week', '%d weeks'],
|
||||||
|
FormatDistanceToken::AboutXMonths => ['about a month', 'about %d months'],
|
||||||
|
FormatDistanceToken::XMonths => ['a month', '%d months'],
|
||||||
|
FormatDistanceToken::AboutXYears => ['about a year', 'about %d years'],
|
||||||
|
FormatDistanceToken::XYears => ['a year', '%d years'],
|
||||||
|
FormatDistanceToken::OverXYears => ['over a year', 'over %d years'],
|
||||||
|
FormatDistanceToken::AlmostXYears => ['almost a year', 'almost %d years']
|
||||||
|
};
|
||||||
|
$value = $typeAndNumber[1] == 1 ? $format[0] : sprintf($format[1], $typeAndNumber[1]);
|
||||||
|
return $dtFrom > $dtTo ? "$value ago" : "in $value";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function requestList(DocumentList $reqs): void
|
public static function requestList(DocumentList $reqs): void
|
||||||
@ -171,3 +208,20 @@ class UI
|
|||||||
</div><?php
|
</div><?php
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum FormatDistanceToken
|
||||||
|
{
|
||||||
|
case LessThanXMinutes;
|
||||||
|
case XMinutes;
|
||||||
|
case AboutXHours;
|
||||||
|
case XHours;
|
||||||
|
case XDays;
|
||||||
|
case AboutXWeeks;
|
||||||
|
case XWeeks;
|
||||||
|
case AboutXMonths;
|
||||||
|
case XMonths;
|
||||||
|
case AboutXYears;
|
||||||
|
case XYears;
|
||||||
|
case OverXYears;
|
||||||
|
case AlmostXYears;
|
||||||
|
}
|
||||||
|
@ -30,8 +30,8 @@ Layout::pageHead('Full Request');?>
|
|||||||
<div class=card-body>
|
<div class=card-body>
|
||||||
<h6 class="card-subtitle text-muted mb-2"><?php
|
<h6 class="card-subtitle text-muted mb-2"><?php
|
||||||
if (!is_null($answered)) { ?>
|
if (!is_null($answered)) { ?>
|
||||||
Answered <?=$answered->format('F j, Y')?> (<?php UI::relativeDate($req->history[0]->asOf); ?>)
|
Answered <?=$answered->format('F j, Y')?>
|
||||||
•<?php
|
(<?=UI::formatDistance('now', $req->history[0]->asOf);?>) •<?php
|
||||||
} ?>
|
} ?>
|
||||||
Prayed <?=number_format($prayed)?> times • Open <?=number_format($daysOpen)?> days
|
Prayed <?=number_format($prayed)?> times • Open <?=number_format($daysOpen)?> days
|
||||||
</h6>
|
</h6>
|
||||||
|
Loading…
Reference in New Issue
Block a user