Start paths
This commit is contained in:
parent
17c2997d3d
commit
3cc25ee126
@ -153,7 +153,7 @@ impl From<(crate::ShoppingCart, Vec<crate::ShoppingCartItem>)> for ShoppingCart
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Hash)]
|
||||||
pub struct Photo {
|
pub struct Photo {
|
||||||
pub id: crate::PhotoId,
|
pub id: crate::PhotoId,
|
||||||
pub file_name: crate::FileName,
|
pub file_name: crate::FileName,
|
||||||
@ -162,7 +162,7 @@ pub struct Photo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Hash)]
|
||||||
pub struct Product {
|
pub struct Product {
|
||||||
pub id: crate::ProductId,
|
pub id: crate::ProductId,
|
||||||
pub name: crate::ProductName,
|
pub name: crate::ProductName,
|
||||||
|
@ -19,7 +19,7 @@ use serde::{Deserialize, Deserializer, Serialize};
|
|||||||
|
|
||||||
pub use crate::encrypt::*;
|
pub use crate::encrypt::*;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, Hash, thiserror::Error)]
|
||||||
pub enum TransformError {
|
pub enum TransformError {
|
||||||
#[error("Given value is below minimal value")]
|
#[error("Given value is below minimal value")]
|
||||||
BelowMinimal,
|
BelowMinimal,
|
||||||
@ -34,7 +34,7 @@ pub type RecordId = i32;
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Hash, Display, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum OrderStatus {
|
pub enum OrderStatus {
|
||||||
#[display(fmt = "Potwierdzone")]
|
#[display(fmt = "Potwierdzone")]
|
||||||
@ -54,7 +54,7 @@ pub enum OrderStatus {
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
#[derive(Copy, Clone, Debug, Hash, Display, Deserialize, Serialize, PartialEq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Role {
|
pub enum Role {
|
||||||
#[display(fmt = "Adminitrator")]
|
#[display(fmt = "Adminitrator")]
|
||||||
@ -80,7 +80,7 @@ impl Role {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Hash, Display, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum QuantityUnit {
|
pub enum QuantityUnit {
|
||||||
#[cfg_attr(feature = "db", sqlx(rename = "g"))]
|
#[cfg_attr(feature = "db", sqlx(rename = "g"))]
|
||||||
@ -96,7 +96,7 @@ pub enum QuantityUnit {
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Hash, Display, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum PaymentMethod {
|
pub enum PaymentMethod {
|
||||||
PayU,
|
PayU,
|
||||||
@ -106,7 +106,7 @@ pub enum PaymentMethod {
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize)]
|
#[derive(Copy, Clone, Debug, Hash, Display, Deserialize, Serialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ShoppingCartState {
|
pub enum ShoppingCartState {
|
||||||
Active,
|
Active,
|
||||||
@ -116,7 +116,7 @@ pub enum ShoppingCartState {
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
#[cfg_attr(feature = "db", sqlx(rename_all = "snake_case"))]
|
||||||
#[derive(Copy, Clone, Debug, Display, Deserialize, Serialize, PartialEq)]
|
#[derive(Copy, Clone, Debug, Hash, Display, Deserialize, Serialize, PartialEq)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Audience {
|
pub enum Audience {
|
||||||
Web,
|
Web,
|
||||||
@ -161,14 +161,14 @@ impl Default for Audience {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Hash, Deref, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Price(NonNegative);
|
pub struct Price(NonNegative);
|
||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Deref, From)]
|
#[derive(Serialize, Deserialize, Default, Debug, Copy, Clone, Hash, Deref, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Quantity(NonNegative);
|
pub struct Quantity(NonNegative);
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ impl<'de> serde::Deserialize<'de> for Email {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Default, Debug, Copy, Clone, Deref, Display)]
|
#[derive(Serialize, Default, Debug, Copy, Clone, Hash, Deref, Display)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct NonNegative(i32);
|
pub struct NonNegative(i32);
|
||||||
|
|
||||||
@ -323,7 +323,7 @@ impl<'de> serde::Deserialize<'de> for NonNegative {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, Display, From)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum Day {
|
pub enum Day {
|
||||||
Monday = 1 << 0,
|
Monday = 1 << 0,
|
||||||
@ -360,7 +360,7 @@ impl TryFrom<i32> for Day {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[derive(Serialize, Deserialize, Deref, Debug)]
|
#[derive(Serialize, Deserialize, Hash, Debug, Deref)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct Days(Vec<Day>);
|
pub struct Days(Vec<Day>);
|
||||||
|
|
||||||
@ -536,26 +536,26 @@ pub struct ProductId(RecordId);
|
|||||||
|
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductName(String);
|
pub struct ProductName(String);
|
||||||
|
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductShortDesc(String);
|
pub struct ProductShortDesc(String);
|
||||||
|
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductLongDesc(String);
|
pub struct ProductLongDesc(String);
|
||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Hash, Deref, Display, From)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct ProductCategory(String);
|
pub struct ProductCategory(String);
|
||||||
|
|
||||||
@ -567,7 +567,7 @@ impl ProductCategory {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Hash)]
|
||||||
pub struct Product {
|
pub struct Product {
|
||||||
pub id: ProductId,
|
pub id: ProductId,
|
||||||
pub name: ProductName,
|
pub name: ProductName,
|
||||||
@ -780,7 +780,7 @@ impl RefreshTokenString {
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Hash, Deref, Display, From)]
|
||||||
pub struct LocalPath(String);
|
pub struct LocalPath(String);
|
||||||
|
|
||||||
impl LocalPath {
|
impl LocalPath {
|
||||||
@ -792,7 +792,7 @@ impl LocalPath {
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Hash, Deref, Display, From)]
|
||||||
pub struct UniqueName(String);
|
pub struct UniqueName(String);
|
||||||
|
|
||||||
impl UniqueName {
|
impl UniqueName {
|
||||||
@ -804,7 +804,7 @@ impl UniqueName {
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Hash, Deref, Display, From)]
|
||||||
pub struct FileName(String);
|
pub struct FileName(String);
|
||||||
|
|
||||||
impl FileName {
|
impl FileName {
|
||||||
@ -816,18 +816,18 @@ impl FileName {
|
|||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Hash, Deref, Display, From)]
|
||||||
pub struct PhotoId(RecordId);
|
pub struct PhotoId(RecordId);
|
||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
#[cfg_attr(feature = "db", derive(sqlx::Type))]
|
||||||
#[cfg_attr(feature = "db", sqlx(transparent))]
|
#[cfg_attr(feature = "db", sqlx(transparent))]
|
||||||
#[derive(Serialize, Deserialize, Debug, Deref, Display, From)]
|
#[derive(Serialize, Deserialize, Debug, Hash, Deref, Display, From)]
|
||||||
pub struct ProductPhotoId(RecordId);
|
pub struct ProductPhotoId(RecordId);
|
||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Hash)]
|
||||||
pub struct Photo {
|
pub struct Photo {
|
||||||
pub id: PhotoId,
|
pub id: PhotoId,
|
||||||
pub local_path: LocalPath,
|
pub local_path: LocalPath,
|
||||||
@ -837,7 +837,7 @@ pub struct Photo {
|
|||||||
|
|
||||||
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
|
||||||
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
#[cfg_attr(feature = "db", derive(sqlx::FromRow))]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Hash)]
|
||||||
pub struct ProductLinkedPhoto {
|
pub struct ProductLinkedPhoto {
|
||||||
pub id: PhotoId,
|
pub id: PhotoId,
|
||||||
pub local_path: LocalPath,
|
pub local_path: LocalPath,
|
||||||
|
@ -24,7 +24,9 @@ macro_rules! fetch_page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
|
fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
|
||||||
orders.stream(streams::interval(500, || Msg::CheckAccessToken));
|
orders
|
||||||
|
.stream(streams::interval(500, || Msg::CheckAccessToken))
|
||||||
|
.subscribe(Msg::UrlChanged);
|
||||||
|
|
||||||
Model {
|
Model {
|
||||||
token: LocalStorage::get("auth-token").ok(),
|
token: LocalStorage::get("auth-token").ok(),
|
||||||
|
@ -40,6 +40,13 @@ impl Page {
|
|||||||
url,
|
url,
|
||||||
&mut orders.proxy(|msg| Msg::Public(public::Msg::Listing(msg))),
|
&mut orders.proxy(|msg| Msg::Public(public::Msg::Listing(msg))),
|
||||||
))),
|
))),
|
||||||
|
["products", rest @ ..] => {
|
||||||
|
seed::log!(rest);
|
||||||
|
Self::Public(PublicPage::Listing(public::listing::init(
|
||||||
|
url,
|
||||||
|
&mut orders.proxy(|msg| Msg::Public(public::Msg::Listing(msg))),
|
||||||
|
)))
|
||||||
|
}
|
||||||
["admin"] => Self::Admin(AdminPage::Landing),
|
["admin"] => Self::Admin(AdminPage::Landing),
|
||||||
_ => Self::Public(PublicPage::Listing(public::listing::init(
|
_ => Self::Public(PublicPage::Listing(public::listing::init(
|
||||||
url,
|
url,
|
||||||
@ -62,7 +69,7 @@ impl<'a> Urls<'a> {
|
|||||||
// Public
|
// Public
|
||||||
|
|
||||||
fn listing(self) -> Url {
|
fn listing(self) -> Url {
|
||||||
self.base_url().add_path_part("listing")
|
self.base_url().add_path_part("products")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn product(self) -> Url {
|
fn product(self) -> Url {
|
||||||
|
@ -4,3 +4,49 @@ pub mod listing;
|
|||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
Listing(listing::Msg),
|
Listing(listing::Msg),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod layout {
|
||||||
|
use seed::prelude::*;
|
||||||
|
use seed::*;
|
||||||
|
|
||||||
|
pub fn view<Msg>(url: Url, content: Node<Msg>, categories: &[String]) -> Node<Msg> {
|
||||||
|
div![
|
||||||
|
C!["flex"],
|
||||||
|
div![
|
||||||
|
C!["flex flex-col w-64 h-screen px-4 py-8 overflow-y-auto border-r"],
|
||||||
|
super::sidebar::view(url, categories)
|
||||||
|
],
|
||||||
|
div![C!["w-full h-full p-4 m-8 overflow-y-auto"], content]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod sidebar {
|
||||||
|
use seed::prelude::*;
|
||||||
|
use seed::*;
|
||||||
|
|
||||||
|
use crate::pages::Urls;
|
||||||
|
|
||||||
|
pub fn view<Msg>(url: Url, categories: &[String]) -> Node<Msg> {
|
||||||
|
let categories = categories
|
||||||
|
.iter()
|
||||||
|
.map(|category| item(url.clone(), category.as_str()));
|
||||||
|
|
||||||
|
div![
|
||||||
|
C!["flex flex-col justify-between mt-6"],
|
||||||
|
aside![ul![categories]]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn item<Msg>(url: Url, category: &str) -> Node<Msg> {
|
||||||
|
let url = Urls::new(url).listing().add_path_part(category);
|
||||||
|
li![
|
||||||
|
C!["flex items-center px-4 py-2 text-gray-700 rounded-md"],
|
||||||
|
a![
|
||||||
|
C!["flex items-center px-4 py-2 text-gray-700 rounded-md"],
|
||||||
|
attrs!["href" => url],
|
||||||
|
span![C!["mx-4 font-medium"], category]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,26 +1,49 @@
|
|||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use seed::app::Orders;
|
use seed::app::Orders;
|
||||||
use seed::prelude::*;
|
use seed::prelude::*;
|
||||||
use seed::*;
|
use seed::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
pub products: Vec<model::api::Product>,
|
url: Url,
|
||||||
|
pub products: HashMap<model::ProductId, model::api::Product>,
|
||||||
pub errors: Vec<String>,
|
pub errors: Vec<String>,
|
||||||
|
pub categories: Vec<String>,
|
||||||
|
pub filters: HashSet<String>,
|
||||||
|
pub visible_products: Vec<model::ProductId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
FetchProducts,
|
FetchProducts,
|
||||||
ProductFetched(fetch::Result<model::api::Products>),
|
ProductFetched(fetch::Result<model::api::Products>),
|
||||||
Shared(crate::shared::Msg)
|
Shared(crate::shared::Msg),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(_url: Url, orders: &mut impl Orders<Msg>) -> Model {
|
pub fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
|
||||||
orders.send_msg(Msg::FetchProducts);
|
let filters = match url.clone().remaining_path_parts().as_slice() {
|
||||||
Model {
|
["products", filters @ ..] => {
|
||||||
products: vec![],
|
filters
|
||||||
errors: vec![],
|
.into_iter()
|
||||||
|
.fold(HashSet::with_capacity(filters.len()), |mut s, filter| {
|
||||||
|
s.insert(String::from(*filter));
|
||||||
|
s
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
_ => HashSet::new(),
|
||||||
|
};
|
||||||
|
orders.send_msg(Msg::FetchProducts);
|
||||||
|
let model = Model {
|
||||||
|
url: url.to_base_url(),
|
||||||
|
products: Default::default(),
|
||||||
|
errors: vec![],
|
||||||
|
categories: vec![],
|
||||||
|
filters,
|
||||||
|
visible_products: vec![],
|
||||||
|
};
|
||||||
|
seed::log!(&model);
|
||||||
|
model
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
@ -31,7 +54,38 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
Msg::ProductFetched(Ok(products)) => {
|
Msg::ProductFetched(Ok(products)) => {
|
||||||
model.products = products.0;
|
model.categories = products
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
|
.fold(HashSet::new(), |mut set, p| {
|
||||||
|
if let Some(category) = p.category.as_deref() {
|
||||||
|
set.insert(String::from(category));
|
||||||
|
}
|
||||||
|
set
|
||||||
|
})
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
model.categories.sort();
|
||||||
|
model.products = {
|
||||||
|
let len = products.0.len();
|
||||||
|
products
|
||||||
|
.0
|
||||||
|
.into_iter()
|
||||||
|
.fold(HashMap::with_capacity(len), |mut m, p| {
|
||||||
|
m.insert(p.id, p);
|
||||||
|
m
|
||||||
|
})
|
||||||
|
};
|
||||||
|
model.visible_products = model
|
||||||
|
.products
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(_, p)| {
|
||||||
|
p.category
|
||||||
|
.as_deref()
|
||||||
|
.filter(|c| model.filters.contains(*c))
|
||||||
|
.map(|_| p.id)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
Msg::ProductFetched(Err(_e)) => {
|
Msg::ProductFetched(Err(_e)) => {
|
||||||
model.errors.push("Failed to load products".into());
|
model.errors.push("Failed to load products".into());
|
||||||
@ -41,14 +95,22 @@ pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(model: &crate::Model, page: &Model) -> Node<Msg> {
|
pub fn view(model: &crate::Model, page: &Model) -> Node<Msg> {
|
||||||
let products = page.products.iter().map(product);
|
let products = page
|
||||||
|
.visible_products
|
||||||
|
.iter()
|
||||||
|
.filter_map(|id| page.products.get(id))
|
||||||
|
.map(product);
|
||||||
|
|
||||||
div![
|
div![
|
||||||
crate::shared::view::public_navbar(model),
|
crate::shared::view::public_navbar(model),
|
||||||
|
super::layout::view(
|
||||||
|
page.url.clone(),
|
||||||
div![
|
div![
|
||||||
C!["grid grid-cols-1 gap-4 lg:grid-cols-6 sm:grid-cols-2"],
|
C!["grid grid-cols-1 gap-4 lg:grid-cols-6 sm:grid-cols-2"],
|
||||||
products
|
products
|
||||||
]
|
],
|
||||||
|
&page.categories
|
||||||
|
)
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user