clickable htmx button for adding search results to your list
This commit is contained in:
parent
1c304e1184
commit
c4976a3efc
4 changed files with 55 additions and 56 deletions
|
@ -8,7 +8,7 @@ table {
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
background-color: darkgray;
|
background-color: ghostwhite;
|
||||||
}
|
}
|
||||||
|
|
||||||
th, td {
|
th, td {
|
||||||
|
@ -16,7 +16,7 @@ th, td {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr:nth-child(odd) {background-color: ghostwhite;}
|
tr:nth-child(even) {background-color: ghostwhite;}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
text-align: end;
|
text-align: end;
|
||||||
|
|
|
@ -3,6 +3,7 @@ use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Redirect, Response},
|
response::{IntoResponse, Redirect, Response},
|
||||||
};
|
};
|
||||||
|
use http::HeaderValue;
|
||||||
use julid::Julid;
|
use julid::Julid;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::{query, query_as, query_scalar, SqlitePool};
|
use sqlx::{query, query_as, query_scalar, SqlitePool};
|
||||||
|
@ -37,22 +38,22 @@ const EMPTY_SEARCH_QUERY_STRUCT: SearchQuery = SearchQuery {
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
|
|
||||||
#[Error]
|
#[Error]
|
||||||
pub struct WatchAddError(#[from] WatchAddErrorKind);
|
pub struct AddError(#[from] AddErrorKind);
|
||||||
|
|
||||||
#[Error]
|
#[Error]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub enum WatchAddErrorKind {
|
pub enum AddErrorKind {
|
||||||
UnknownDBError,
|
UnknownDBError,
|
||||||
NotSignedIn,
|
NotSignedIn,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoResponse for WatchAddError {
|
impl IntoResponse for AddError {
|
||||||
fn into_response(self) -> Response {
|
fn into_response(self) -> Response {
|
||||||
match &self.0 {
|
match &self.0 {
|
||||||
WatchAddErrorKind::UnknownDBError => {
|
AddErrorKind::UnknownDBError => {
|
||||||
(StatusCode::INTERNAL_SERVER_ERROR, format!("{self}")).into_response()
|
(StatusCode::INTERNAL_SERVER_ERROR, format!("{self}")).into_response()
|
||||||
}
|
}
|
||||||
WatchAddErrorKind::NotSignedIn => (
|
AddErrorKind::NotSignedIn => (
|
||||||
StatusCode::OK,
|
StatusCode::OK,
|
||||||
"Ope, you need to sign in first!".to_string(),
|
"Ope, you need to sign in first!".to_string(),
|
||||||
)
|
)
|
||||||
|
@ -94,7 +95,7 @@ pub struct PostAddNewWatch {
|
||||||
|
|
||||||
#[derive(Debug, Default, Deserialize, PartialEq, Eq)]
|
#[derive(Debug, Default, Deserialize, PartialEq, Eq)]
|
||||||
pub struct PostAddExistingWatch {
|
pub struct PostAddExistingWatch {
|
||||||
pub id: String,
|
pub watch: String,
|
||||||
pub public: bool,
|
pub public: bool,
|
||||||
pub watched_already: bool,
|
pub watched_already: bool,
|
||||||
}
|
}
|
||||||
|
@ -107,18 +108,12 @@ pub async fn get_add_new_watch(auth: AuthSession) -> impl IntoResponse {
|
||||||
AddNewWatchPage { user: auth.user }
|
AddNewWatchPage { user: auth.user }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QuestQuest {
|
|
||||||
pub user: Julid,
|
|
||||||
pub is_public: bool,
|
|
||||||
pub already_watched: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a Watch to your watchlist (side effects system-add)
|
/// Add a Watch to your watchlist (side effects system-add)
|
||||||
pub async fn post_add_new_watch(
|
pub async fn post_add_new_watch(
|
||||||
auth: AuthSession,
|
auth: AuthSession,
|
||||||
State(pool): State<SqlitePool>,
|
State(pool): State<SqlitePool>,
|
||||||
Form(form): Form<PostAddNewWatch>,
|
Form(form): Form<PostAddNewWatch>,
|
||||||
) -> Result<impl IntoResponse, WatchAddError> {
|
) -> Result<impl IntoResponse, AddError> {
|
||||||
if let Some(user) = auth.user {
|
if let Some(user) = auth.user {
|
||||||
{
|
{
|
||||||
let release_date = year_to_epoch(form.year.as_deref());
|
let release_date = year_to_epoch(form.year.as_deref());
|
||||||
|
@ -130,31 +125,27 @@ pub async fn post_add_new_watch(
|
||||||
added_by: user.id,
|
added_by: user.id,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let quest = QuestQuest {
|
|
||||||
|
let watch_id = add_new_watch_impl(&pool, &watch).await?;
|
||||||
|
let quest = WatchQuest {
|
||||||
user: user.id,
|
user: user.id,
|
||||||
is_public: !form.private,
|
is_public: !form.private,
|
||||||
already_watched: form.watched_already,
|
already_watched: form.watched_already,
|
||||||
|
watch: watch_id,
|
||||||
};
|
};
|
||||||
|
add_watch_quest_impl(&pool, &quest)
|
||||||
let watch_id = add_new_watch_impl(&pool, &watch, Some(quest)).await?;
|
.await
|
||||||
|
.map_err(|_| AddErrorKind::UnknownDBError)?;
|
||||||
|
|
||||||
let location = format!("/watch/{watch_id}");
|
let location = format!("/watch/{watch_id}");
|
||||||
Ok(Redirect::to(&location))
|
Ok(Redirect::to(&location))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(WatchAddErrorKind::NotSignedIn.into())
|
Err(AddErrorKind::NotSignedIn.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn add_new_watch_impl(
|
async fn add_new_watch_impl(db_pool: &SqlitePool, watch: &Watch) -> Result<Julid, AddError> {
|
||||||
db_pool: &SqlitePool,
|
|
||||||
watch: &Watch,
|
|
||||||
quest: Option<QuestQuest>,
|
|
||||||
) -> Result<Julid, WatchAddError> {
|
|
||||||
let mut tx = db_pool
|
|
||||||
.begin()
|
|
||||||
.await
|
|
||||||
.map_err(|_| WatchAddErrorKind::UnknownDBError)?;
|
|
||||||
let watch_id: Julid = query_scalar(ADD_WATCH_QUERY)
|
let watch_id: Julid = query_scalar(ADD_WATCH_QUERY)
|
||||||
.bind(&watch.title)
|
.bind(&watch.title)
|
||||||
.bind(watch.kind)
|
.bind(watch.kind)
|
||||||
|
@ -162,44 +153,43 @@ async fn add_new_watch_impl(
|
||||||
.bind(&watch.metadata_url)
|
.bind(&watch.metadata_url)
|
||||||
.bind(watch.added_by)
|
.bind(watch.added_by)
|
||||||
.bind(watch.length)
|
.bind(watch.length)
|
||||||
.fetch_one(&mut *tx)
|
.fetch_one(db_pool)
|
||||||
.await
|
.await
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
tracing::error!("Got error: {err}");
|
tracing::error!("Got error: {err}");
|
||||||
WatchAddErrorKind::UnknownDBError
|
AddErrorKind::UnknownDBError
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if let Some(quest) = quest {
|
|
||||||
query(ADD_WATCH_QUEST_QUERY)
|
|
||||||
.bind(quest.user)
|
|
||||||
.bind(watch_id)
|
|
||||||
.bind(quest.is_public)
|
|
||||||
.bind(quest.already_watched)
|
|
||||||
.execute(&mut *tx)
|
|
||||||
.await
|
|
||||||
.map_err(|err| {
|
|
||||||
tracing::error!("Got error: {err}");
|
|
||||||
WatchAddErrorKind::UnknownDBError
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
tx.commit().await.map_err(|err| {
|
|
||||||
tracing::error!("Got error: {err}");
|
|
||||||
WatchAddErrorKind::UnknownDBError
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(watch_id)
|
Ok(watch_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a Watch to your watchlist by selecting it with a checkbox
|
/// Add a Watch to your watchlist by selecting it with a checkbox
|
||||||
pub async fn post_add_watch_quest(
|
pub async fn post_add_watch_quest(
|
||||||
_auth: AuthSession,
|
auth: AuthSession,
|
||||||
State(_pool): State<SqlitePool>,
|
State(pool): State<SqlitePool>,
|
||||||
Form(_form): Form<PostAddExistingWatch>,
|
Form(form): Form<PostAddExistingWatch>,
|
||||||
) -> impl IntoResponse {
|
) -> Result<impl IntoResponse, AddError> {
|
||||||
todo!()
|
if let Some(user) = auth.user {
|
||||||
|
let quest = WatchQuest {
|
||||||
|
user: user.id,
|
||||||
|
watch: Julid::from_string(&form.watch).unwrap(),
|
||||||
|
is_public: form.public,
|
||||||
|
already_watched: form.watched_already,
|
||||||
|
};
|
||||||
|
add_watch_quest_impl(&pool, &quest)
|
||||||
|
.await
|
||||||
|
.map_err(|_| AddErrorKind::UnknownDBError)?;
|
||||||
|
let resp = "<style=\"background-color:green\">✓</style>";
|
||||||
|
Ok(resp.into_response())
|
||||||
|
} else {
|
||||||
|
let resp = Redirect::to("/login");
|
||||||
|
let mut resp = resp.into_response();
|
||||||
|
resp.headers_mut()
|
||||||
|
.insert("HX-Redirect", HeaderValue::from_str("/login").unwrap());
|
||||||
|
Ok(resp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn _add_watch_quest_impl(pool: &SqlitePool, quest: &WatchQuest) -> Result<(), ()> {
|
pub async fn add_watch_quest_impl(pool: &SqlitePool, quest: &WatchQuest) -> Result<(), ()> {
|
||||||
query(ADD_WATCH_QUEST_QUERY)
|
query(ADD_WATCH_QUEST_QUERY)
|
||||||
.bind(quest.user)
|
.bind(quest.user)
|
||||||
.bind(quest.watch)
|
.bind(quest.watch)
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% when None %} <!-- this is for the `when` statement -->
|
{% when None %}
|
||||||
<div class="header_logged_out">
|
<div class="header_logged_out">
|
||||||
<a href="/login">log in</a> or <a href="/signup">sign up</a>?
|
<a href="/login">log in</a> or <a href="/signup">sign up</a>?
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,4 +2,13 @@
|
||||||
<td><span class="watchtitle">{{watch.title}}</span></td>
|
<td><span class="watchtitle">{{watch.title}}</span></td>
|
||||||
<td>{{watch.kind}}</td>
|
<td>{{watch.kind}}</td>
|
||||||
<td> {% call m::get_or_default(watch.year(), "when??") -%}</td>
|
<td> {% call m::get_or_default(watch.year(), "when??") -%}</td>
|
||||||
|
<td>
|
||||||
|
<form id="add-watch-{{watch.id}}">
|
||||||
|
<input type="hidden" name="watch" value="{{watch.id}}">
|
||||||
|
<input type="hidden" name="public" value="true">
|
||||||
|
<input type="hidden" name="watched_already" value="false">
|
||||||
|
<button hx-post="/add/watch" hx-target="#add-watch-{{watch.id}}" hx-trigger="click"
|
||||||
|
hx-swap="OuterHTML">wanna watch?</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
Loading…
Reference in a new issue