diff --git a/migrations/20240907190149_add-links.sql b/migrations/20240907190149_add-links.sql
index 67d3ad5..3e40a46 100644
--- a/migrations/20240907190149_add-links.sql
+++ b/migrations/20240907190149_add-links.sql
@@ -1,3 +1,4 @@
alter table "public"."series" add column source text not null;
+alter table "public"."series" add column source_url text not null;
alter table "public"."series" add column imdb text null;
alter table "public"."series" add column wikipedia text null
diff --git a/sql/insert_series.sql b/sql/insert_series.sql
index 661d629..6349a77 100644
--- a/sql/insert_series.sql
+++ b/sql/insert_series.sql
@@ -1 +1 @@
-insert into series (name, source, imdb, wikipedia) values ($1, $2, $3, $4);
+insert into series (name, source, source_url, imdb, wikipedia) values ($1, $2, $3, $4, $5);
diff --git a/src/app/series/add.rs b/src/app/series/add.rs
index 99d84da..4d02f08 100644
--- a/src/app/series/add.rs
+++ b/src/app/series/add.rs
@@ -1,3 +1,5 @@
+use crate::app::series::Source;
+
use leptos::*;
use leptos_router::*;
@@ -25,9 +27,21 @@ pub fn AddSeries() -> impl IntoView {
/>
-
+
+
+
+
+
@@ -60,7 +74,8 @@ pub fn AddSeries() -> impl IntoView {
#[server(AddSeries)]
pub async fn add_series(
name: String,
- source: String,
+ source: Source,
+ source_url: String,
imdb: String,
wikipedia: String,
) -> Result<(), ServerFnError> {
@@ -72,7 +87,8 @@ pub async fn add_series(
sqlx::query(&s)
.persistent(true)
.bind(name)
- .bind(source)
+ .bind(source.to_string())
+ .bind(source_url)
.bind(if imdb.is_empty() { None } else { Some(imdb) })
.bind(if wikipedia.is_empty() {
None
diff --git a/src/app/series/mod.rs b/src/app/series/mod.rs
index b0cc1fe..3464942 100644
--- a/src/app/series/mod.rs
+++ b/src/app/series/mod.rs
@@ -1,9 +1,10 @@
+use std::fmt::Display;
+
use self::add::AddSeries;
+
use leptos::*;
use leptos_router::*;
use serde::{Deserialize, Serialize};
-#[cfg(feature = "ssr")]
-use sqlx::FromRow;
use uuid::Uuid;
pub mod add;
@@ -102,16 +103,92 @@ pub fn format_errors(errors: RwSignal) -> impl IntoView {
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
-#[cfg_attr(feature = "ssr", derive(FromRow))]
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub enum Source {
+ Disney,
+ Hulu,
+ Paramount,
+ Prime,
+ Max,
+ Netflix,
+ Shudder,
+}
+
+impl Display for Source {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Source::Disney => f.write_str("Disney"),
+ Source::Hulu => f.write_str("Hulu"),
+ Source::Paramount => f.write_str("Paramount"),
+ Source::Prime => f.write_str("Prime"),
+ Source::Max => f.write_str("Max"),
+ Source::Netflix => f.write_str("Netflix"),
+ Source::Shudder => f.write_str("Shudder"),
+ }
+ }
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Series {
id: Uuid,
name: String,
- source: String,
+ source: Source,
+ source_url: String,
imdb: Option,
wikipedia: Option,
}
+#[cfg(feature = "ssr")]
+mod ssr {
+ use super::{Series, Source};
+ use sqlx::{postgres::PgRow, prelude::*};
+
+ impl<'r> FromRow<'r, PgRow> for Series {
+ fn from_row(row: &'r PgRow) -> Result {
+ let id = row.try_get("id")?;
+ let name = row.try_get("name")?;
+ let source: String = row.try_get("source")?;
+
+ let source_enum: Source =
+ source
+ .try_into()
+ .map_err(|e: String| sqlx::Error::ColumnDecode {
+ index: "source".to_string(),
+ source: e.into(),
+ })?;
+ let source_url = row.try_get("source_url")?;
+ let imdb = row.try_get("imdb")?;
+ let wikipedia = row.try_get("wikipedia")?;
+
+ Ok(Series {
+ id,
+ name,
+ source_url,
+ imdb,
+ wikipedia,
+ source: source_enum,
+ })
+ }
+ }
+
+ impl TryFrom for Source {
+ type Error = String;
+
+ fn try_from(value: String) -> Result {
+ match value.to_lowercase().as_str() {
+ "disney" => Ok(Self::Disney),
+ "hulu" => Ok(Self::Hulu),
+ "paramount" => Ok(Self::Paramount),
+ "prime" => Ok(Self::Prime),
+ "max" => Ok(Self::Max),
+ "netflix" => Ok(Self::Netflix),
+ "shudder" => Ok(Self::Shudder),
+ _ => Err(format!("Unrecognized source: {value}")),
+ }
+ }
+ }
+}
+
#[server]
pub async fn get_all() -> Result, ServerFnError> {
use crate::db::load_statement;
diff --git a/src/app/series/view.rs b/src/app/series/view.rs
index 82d0f60..e9e3b76 100644
--- a/src/app/series/view.rs
+++ b/src/app/series/view.rs
@@ -14,25 +14,13 @@ pub fn ViewSeries() -> impl IntoView {
let id = move || {
ps.with(|ps| {
ps.as_ref()
- .map(|ps| ps.id.clone())
+ .map(|ps| ps.id)
.expect("Failed to parse Id value from query string!")
})
};
- let details = create_resource(
- move || id(),
- |id| async move { get_series_details(id).await },
- );
+ let details = create_resource(id, |id| async move { get_series_details(id).await });
view! {
-
{details.get().map(format_series_details)}
@@ -44,10 +32,20 @@ pub fn ViewSeries() -> impl IntoView {
fn loading() -> impl IntoView {
view! {
- {format_field("Name", view!())}
- {format_field("Source", view!())}
- {format_field("IMDB", view!())}
- {format_field("Wikpedia", view!())}
+
+
+ x
+
+
+
+
+
+
+
+
}
}
@@ -57,22 +55,44 @@ fn format_series_details(
Ok(view! {
{details.map(|details| view! {
- {format_field("Name", details.name)}
- {format_field("Source", details.source)}
- {format_field("IMDB", details.imdb)}
- {format_field("Wikipedia", details.wikipedia)}
+
+
+ x
+
+
{details.name}
+
+
})
}
})
}
-fn format_field(label: &'static str, f: F) -> impl IntoView {
+#[component]
+fn OptionalUrlButton(label: &'static str, opt_url: Option) -> impl IntoView {
view! {
-
+
+ {opt_url.as_ref().map(|url| view! {
+
+ {label}
+
+ })}
+
}
}