Skip to content

Commit

Permalink
imp: Display new feed errors in the modal
Browse files Browse the repository at this point in the history
For now, responses to form submits redirect to a new page. However,
I’d like the modal forms errors to be displayed directly in the modal,
without redirecting to a new page.

Since the modal is handled with a Turbo Frame, it should not be too
complicated. Except that's impossible. I need to set the frame attribute
target="_top" in order to redirect after a success, but I would need the
opposite in case of an error.

There are some discussions to handle this use case directly with Turbo,
but until an official solution appears, I will use this hack which use
Turbo Stream to update the modal content. I don’t think it’s a perfect
solution, so I’m not going to generalize it in the application. The new
feed form is important to handle correctly since errors are common (e.g.
a feed cannot be found).

Reference: hotwired/turbo#138 (comment)
  • Loading branch information
marienfressinaud committed Jan 12, 2022
1 parent 1f2d682 commit 7045806
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 56 deletions.
2 changes: 2 additions & 0 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public function __construct()
$router = Router::load();
$this->engine = new \Minz\Engine($router);
\Minz\Url::setRouter($router);

\Minz\Output\View::$extensions_to_content_types['.turbo_stream.phtml'] = 'text/vnd.turbo-stream.html';
}

/**
Expand Down
21 changes: 16 additions & 5 deletions src/controllers/Feeds.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,16 @@ public function index($request)
/**
* Show the page to add a feed.
*
* @request_param string from The page to redirect to after creation
* @request_param string from
* The page to redirect to after creation (default is /feeds)
*
* @response 302 /login?redirect_to=:from if not connected
* @response 200
*/
public function new($request)
{
$user = auth\CurrentUser::get();
$from = $request->param('from');
$from = $request->param('from', \Minz\Url::for('feeds'));

if (!$user) {
return Response::redirect('login', ['redirect_to' => $from]);
Expand Down Expand Up @@ -103,8 +104,18 @@ public function create($request)
return Response::redirect('login', ['redirect_to' => $from]);
}

if ($request->isAccepting('text/vnd.turbo-stream.html')) {
// This allows to display the errors within the modal instead of
// sending a whole new page. This is a bit hacky so I'm going
// to use this method only where absolutely needed.
// @see https://github.com/hotwired/turbo/issues/138#issuecomment-847699281
$view_file = 'feeds/new.turbo_stream.phtml';
} else {
$view_file = 'feeds/new.phtml';
}

if (!\Minz\CSRF::validate($csrf)) {
return Response::badRequest('feeds/new.phtml', [
return Response::badRequest($view_file, [
'url' => $url,
'from' => $from,
'error' => _('A security verification failed: you should retry to submit the form.'),
Expand All @@ -121,7 +132,7 @@ public function create($request)

$errors = $default_link->validate();
if ($errors) {
return Response::badRequest('feeds/new.phtml', [
return Response::badRequest($view_file, [
'url' => $url,
'from' => $from,
'errors' => $errors,
Expand All @@ -136,7 +147,7 @@ public function create($request)

$feed_urls = $default_link->feedUrls();
if (count($feed_urls) === 0) {
return Response::badRequest('feeds/new.phtml', [
return Response::badRequest($view_file, [
'url' => $url,
'from' => $from,
'errors' => [
Expand Down
52 changes: 52 additions & 0 deletions src/views/feeds/_new.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<turbo-frame id="modal-feeds-new" target="_top">
<div class="section">
<div class="section__title">
<h1 id="modal-title"><?= _('New feed') ?></h1>
</div>

<form method="post" action="<?= url('create feed') ?>">
<?php if ($error): ?>
<p class="form__error">
<?= $error ?>
</p>
<?php endif; ?>

<input type="hidden" name="csrf" value="<?= $csrf_token ?>" />
<input type="hidden" name="from" value="<?= $from ?>" />

<div class="form-group <?= isset($errors['url']) ? 'form-group--invalid' : '' ?>">
<label for="url">
<?= _('What’s the address of the website or feed to follow?') ?>
</label>

<input
id="url"
name="url"
type="url"
required
value="<?= $url ?>"
autocomplete="off"
autofocus
aria-describedby="url-caption"
/>

<?php if (isset($errors['url'])): ?>
<p class="form-group__error">
<?= icon('error') ?>
<?= $errors['url'] ?>
</p>
<?php endif; ?>

<p class="form-group__caption" id="url-caption">
<?= _('It can be copy-paste from the <abbr>URL</abbr> bar, at the top of your browser.') ?>
</p>
</div>

<div class="form__actions">
<button type="submit" class="button--primary">
<?= _('Add the feed') ?>
</button>
</div>
</form>
</div>
</turbo-frame>
56 changes: 6 additions & 50 deletions src/views/feeds/new.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -10,53 +10,9 @@
]);
?>

<div class="section">
<div class="section__title">
<h1 id="modal-title"><?= _('New feed') ?></h1>
</div>

<form method="post" action="<?= url('create feed') ?>">
<?php if ($error): ?>
<p class="form__error">
<?= $error ?>
</p>
<?php endif; ?>

<input type="hidden" name="csrf" value="<?= $csrf_token ?>" />
<input type="hidden" name="from" value="<?= $from ?>" />

<div class="form-group <?= isset($errors['url']) ? 'form-group--invalid' : '' ?>">
<label for="url">
<?= _('What’s the address of the website or feed to follow?') ?>
</label>

<input
id="url"
name="url"
type="url"
required
value="<?= $url ?>"
autocomplete="off"
autofocus
aria-describedby="url-caption"
/>

<?php if (isset($errors['url'])): ?>
<p class="form-group__error">
<?= icon('error') ?>
<?= $errors['url'] ?>
</p>
<?php endif; ?>

<p class="form-group__caption" id="url-caption">
<?= _('It can be copy-paste from the <abbr>URL</abbr> bar, at the top of your browser.') ?>
</p>
</div>

<div class="form__actions">
<button type="submit" class="button--primary">
<?= _('Add the feed') ?>
</button>
</div>
</form>
</div>
<?= $this->include('feeds/_new.phtml', [
'url' => $url,
'from' => $from,
'errors' => $errors,
'error' => $error,
]); ?>
10 changes: 10 additions & 0 deletions src/views/feeds/new.turbo_stream.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<turbo-stream action="replace" target="modal-feeds-new">
<template>
<?= $this->include('feeds/_new.phtml', [
'url' => $url,
'from' => $from,
'errors' => $errors,
'error' => $error,
]); ?>
</template>
</turbo-stream>

0 comments on commit 7045806

Please sign in to comment.