Opening hours completed. Leptos upgraded to 0.5.2.
This commit is contained in:
@@ -15,3 +15,5 @@ playwright/.cache/
|
||||
/.idea/modules.xml
|
||||
/.idea/rezervovator.iml
|
||||
/.idea/vcs.xml
|
||||
/.settings/
|
||||
/.vscode/
|
||||
|
||||
Generated
+57
-59
@@ -206,7 +206,7 @@ dependencies = [
|
||||
"serde_urlencoded",
|
||||
"smallvec",
|
||||
"socket2 0.5.4",
|
||||
"time 0.3.22",
|
||||
"time",
|
||||
"url",
|
||||
]
|
||||
|
||||
@@ -658,17 +658,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.26"
|
||||
version = "0.4.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"time 0.1.45",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -808,7 +808,7 @@ dependencies = [
|
||||
"rand",
|
||||
"sha2 0.10.7",
|
||||
"subtle",
|
||||
"time 0.3.22",
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
@@ -1233,7 +1233,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -1636,9 +1636,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d3885e75a25bbf43c95350cf2f6b9f5228a3d911e28512c44c2a6c8aa49e9c9"
|
||||
checksum = "f98f0fe11faa66358ff8c2ee48881c54f8f216ecddabfc5b69cdc2e90c8e337b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"leptos_config",
|
||||
@@ -1656,9 +1656,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_actix"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd04ab9afac818fe45695b8e1f103714e612135b42519a21761c730fc9223c14"
|
||||
checksum = "7f50f8c459143ef36c6dce5786e33e48d46dfb6829af87c985d65fb3b0b402aa"
|
||||
dependencies = [
|
||||
"actix-http",
|
||||
"actix-web",
|
||||
@@ -1676,9 +1676,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_config"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3936a83035a4ec03487792d8c9c2c5ad00c269d09701d102630ac5c31caa463"
|
||||
checksum = "e0f0e1a9a583d943b19c740c82a3ec69224c979af90f40738d93ec59ee1475bb"
|
||||
dependencies = [
|
||||
"config",
|
||||
"regex",
|
||||
@@ -1689,9 +1689,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_dom"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6cbea8aeea07633b3559818fa963c03857751fbafc6bb4a73c995662836070e1"
|
||||
checksum = "111391d1ccbc3355344f90f0893f4137db13a7f98d53fede0a3613c522ebaf19"
|
||||
dependencies = [
|
||||
"async-recursion",
|
||||
"cfg-if",
|
||||
@@ -1719,9 +1719,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_hot_reload"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b56ec18e255737108b4f4d570c1c4f036f54a9989befe2658758500b636ebda4"
|
||||
checksum = "a6902fabee84955a85a6cdebf8ddfbfb134091087b172e32ebb26e571d4640ca"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"camino",
|
||||
@@ -1737,9 +1737,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_integration_utils"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77e1faf41644272929c47993af12928a51c0a03a1ed7ee55afcacf4a3a02073c"
|
||||
checksum = "eb816f3c809227b090b538994368a756d494c829b07c1bd312d07263552b8c87"
|
||||
dependencies = [
|
||||
"futures",
|
||||
"leptos",
|
||||
@@ -1751,9 +1751,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_macro"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dae8be584ba63e002cec113e0a831f2ba17ad452104781a2b1b65555db049779"
|
||||
checksum = "e68201041cc5af68f7eb35015336827a36c543d87dcf2403117d7244db1f14a0"
|
||||
dependencies = [
|
||||
"attribute-derive",
|
||||
"cfg-if",
|
||||
@@ -1774,9 +1774,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_meta"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "013e23a79d48c6eee6063b162e5ba0beb7d1a42c07361e4c16effb916160a5f0"
|
||||
checksum = "b64d2b4bd0ab25a4897179ee603f2fa8178da6c9f97ef3efd4fa46580fd7efc1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"indexmap 2.0.0",
|
||||
@@ -1788,15 +1788,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_reactive"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90ec5366c79892fa8232dcfa6f05d610d0fd780af155fea8c466e77da18e744f"
|
||||
checksum = "282e84ae3e3eb30ab1eb1c881bfeea8a3cb6d6c683dc99f26f2f69ee240b148d"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"cfg-if",
|
||||
"futures",
|
||||
"indexmap 2.0.0",
|
||||
"js-sys",
|
||||
"paste",
|
||||
"pin-project",
|
||||
"rustc-hash",
|
||||
"self_cell",
|
||||
@@ -1814,14 +1815,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_router"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f55951a1e4ee0b9c26e4ebc0c09ecc4b7fffbefecb912c72db0c5dfa33b1584c"
|
||||
checksum = "d5ca4422fdfba8af03d347d346f9364a4393ad36e227a018567192395285cf65"
|
||||
dependencies = [
|
||||
"cached",
|
||||
"cfg-if",
|
||||
"common_macros",
|
||||
"gloo-net",
|
||||
"itertools 0.11.0",
|
||||
"js-sys",
|
||||
"lazy_static",
|
||||
"leptos",
|
||||
@@ -1845,9 +1847,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "leptos_server"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f4f7221a323c029877ffb09e97d38cc805f1a5821f9554ecf0e7f6852100c"
|
||||
checksum = "e67f3810352bab860bcfa85f1760de4bd6e82cd72b14a97779d9168d37661bbf"
|
||||
dependencies = [
|
||||
"inventory",
|
||||
"lazy_static",
|
||||
@@ -1986,9 +1988,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
@@ -2029,7 +2031,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
@@ -2436,9 +2438,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.4"
|
||||
version = "1.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f"
|
||||
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
@@ -2447,9 +2461,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.7.2"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
@@ -2511,6 +2525,7 @@ dependencies = [
|
||||
"leptos_meta",
|
||||
"leptos_router",
|
||||
"pwhash",
|
||||
"regex",
|
||||
"rust_decimal",
|
||||
"serde",
|
||||
"sqlx",
|
||||
@@ -2809,9 +2824,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server_fn"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29eefae61211e81059a092a3428612c475a3a28e0ea4fb3fd49b0a940d837f84"
|
||||
checksum = "0186f969a1f9572af27159b8273252abf9a6a38934130fe6f3ae0e439d48cf14"
|
||||
dependencies = [
|
||||
"ciborium",
|
||||
"const_format",
|
||||
@@ -2834,9 +2849,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server_fn_macro"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f68140099f8e55bd526dc176d17d341189bf669d45216c4797ddc344610a84a4"
|
||||
checksum = "1dbc70e4f185ff2b5c11f02a91baf830f33e456e0571d0680d1d76999ed242ed"
|
||||
dependencies = [
|
||||
"const_format",
|
||||
"proc-macro-error",
|
||||
@@ -2849,9 +2864,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "server_fn_macro_default"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eee874f357d640ad221ba0c27c2559fa3d1434f7f7bbf688a34118518c5924b7"
|
||||
checksum = "d8aaf8cf1f5dde82d3f37548732a4852f65d5279b4ae40add5a2a3c9e559f662"
|
||||
dependencies = [
|
||||
"server_fn_macro",
|
||||
"syn 2.0.28",
|
||||
@@ -3312,17 +3327,6 @@ dependencies = [
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.22"
|
||||
@@ -3650,12 +3654,6 @@ dependencies = [
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
||||
+6
-5
@@ -12,21 +12,22 @@ actix-web = { version = "4.4.0", optional = true, features = ["macros"] }
|
||||
actix-session = { version = "0.8.0", optional = true, features = ["cookie-session"] }
|
||||
console_error_panic_hook = "0.1"
|
||||
cfg-if = "1"
|
||||
leptos = { version = "0.5.0" }
|
||||
leptos_meta = { version = "0.5.0" }
|
||||
leptos_actix = { version = "0.5.0", optional = true }
|
||||
leptos_router = { version = "0.5.0" }
|
||||
leptos = { version = "0.5.2" }
|
||||
leptos_meta = { version = "0.5.2" }
|
||||
leptos_actix = { version = "0.5.2", optional = true }
|
||||
leptos_router = { version = "0.5.2" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
wasm-bindgen = "=0.2.87"
|
||||
web-sys = { version = "0.3.61", features = ["Navigator"] }
|
||||
lazy_static = "1.4.0"
|
||||
chrono = "0.4.26"
|
||||
chrono = { version = "0.4.31", features = ["serde"]}
|
||||
sqlx = { version = "0.7.1", optional = true, features = ["runtime-tokio-rustls", "postgres", "chrono", "rust_decimal"] }
|
||||
rust_decimal = "1.31.0"
|
||||
uuid = {version = "1.4.1", features = ["v4"]}
|
||||
validator = {version = "0.16.1", features = ["derive"]}
|
||||
pwhash = "1.0.0"
|
||||
futures-util = "0.3.28"
|
||||
regex = "1.10.2"
|
||||
|
||||
[features]
|
||||
csr = ["leptos/csr", "leptos_meta/csr", "leptos_router/csr"]
|
||||
|
||||
+176
-9
@@ -1,9 +1,14 @@
|
||||
//use chrono::{NaiveDate, NaiveTime, Weekday};
|
||||
//use rust_decimal::Decimal;
|
||||
#![allow(unused_variables)]
|
||||
|
||||
use chrono::{NaiveTime, Weekday};
|
||||
use lazy_static::lazy_static;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
//use uuid::Uuid;
|
||||
use validator::Validate;
|
||||
use validator::{Validate, ValidationError};
|
||||
use crate::error::AppError;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub enum ApiResponse<T> {
|
||||
@@ -114,6 +119,176 @@ impl PwdChange {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Default)]
|
||||
#[cfg_attr(feature = "ssr", derive(sqlx::FromRow))]
|
||||
pub struct OpeningHour {
|
||||
id: i32,
|
||||
pub day: i32,
|
||||
pub from: NaiveTime,
|
||||
pub to: NaiveTime,
|
||||
pub discount: Option<i32>
|
||||
}
|
||||
|
||||
impl OpeningHour {
|
||||
pub fn id(&self) -> i32 {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct DayHours(pub Vec<DayHour>);
|
||||
|
||||
impl DayHours {
|
||||
|
||||
pub fn try_new(hours: &str) -> Result<Self, AppError> {
|
||||
if hours.is_empty() {
|
||||
return Ok(Self(Vec::new()))
|
||||
}
|
||||
|
||||
let times = hours.split(",")
|
||||
.map(|h| h.trim())
|
||||
.map(|h| DayHour::try_from(h))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if times.contains(&Err(AppError::HourParseError)) {
|
||||
return Err(AppError::HourParseError)
|
||||
}
|
||||
|
||||
Ok(Self(times.into_iter().map(|h| h.unwrap()).collect()))
|
||||
}
|
||||
|
||||
pub fn hours(&self) -> &Vec<DayHour> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ToString for DayHours {
|
||||
fn to_string(&self) -> String {
|
||||
if self.0.is_empty() {
|
||||
return "".to_string()
|
||||
}
|
||||
|
||||
self.0.iter().map(|h| {
|
||||
let discount = if let Some(d) = h.discount() {
|
||||
format!(" ({})", d).to_string()
|
||||
} else { "".to_string() };
|
||||
format!("{} - {}{}", h.from().format("%H:%M"), h.to().format("%H:%M"), discount).to_string()})
|
||||
.collect::<Vec<String>>()
|
||||
.join(", ")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct DayHour {
|
||||
from: NaiveTime,
|
||||
to: NaiveTime,
|
||||
discount: Option<i32>
|
||||
}
|
||||
|
||||
impl DayHour {
|
||||
pub fn new(from: NaiveTime, to: NaiveTime, discount: Option<i32>) -> Self {
|
||||
Self { from, to, discount }
|
||||
}
|
||||
|
||||
pub fn from(&self) -> NaiveTime {
|
||||
self.from
|
||||
}
|
||||
pub fn to(&self) -> NaiveTime {
|
||||
self.to
|
||||
}
|
||||
pub fn discount(&self) -> Option<i32> {
|
||||
self.discount
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for DayHour {
|
||||
type Error = AppError;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
value.as_str().try_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for DayHour {
|
||||
type Error = AppError;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
if value.is_empty() {
|
||||
return Err(AppError::HourParseError)
|
||||
}
|
||||
|
||||
let times = value.split("-")
|
||||
.map(|t| t.trim()).collect::<Vec<_>>();
|
||||
|
||||
if times.len() != 2 {
|
||||
return Err(AppError::HourParseError)
|
||||
}
|
||||
|
||||
let from = NaiveTime::parse_from_str(times.get(0).unwrap(), "%H:%M");
|
||||
let to = NaiveTime::parse_from_str(times.get(1).unwrap(), "%H:%M");
|
||||
|
||||
if from.is_err() || to.is_err() {
|
||||
return Err(AppError::HourParseError)
|
||||
}
|
||||
|
||||
Ok(DayHour {
|
||||
from: from.unwrap(),
|
||||
to: to.unwrap(),
|
||||
discount: None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_hours(value: &WeekHours) -> Result<(), ValidationError> {
|
||||
if value.hours().is_empty() {
|
||||
return Ok(())
|
||||
}
|
||||
if let Ok(h) = DayHours::try_new(value.hours()) {
|
||||
for hr in h.hours() {
|
||||
if hr.from() >= hr.to() { return Err(ValidationError::new("TO_BEFORE_FROM")) }
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref RE_HOURS: Regex = Regex::new(r"^$|(^\d{2}:\d{2} ?- ?\d{2}:\d{2} ?(\(\d+\))?,? ?)+").unwrap();
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, Validate)]
|
||||
#[validate(schema(function = "validate_hours", message = "Time 'to' must be after time 'from'"))]
|
||||
pub struct WeekHours {
|
||||
day: Weekday,
|
||||
#[validate(regex(path = "RE_HOURS", message = "Hours must be in HH:MM - HH:MM format"))]
|
||||
hours: String
|
||||
}
|
||||
|
||||
impl Default for WeekHours {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
day: Weekday::Mon,
|
||||
hours: String::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WeekHours {
|
||||
pub fn new(day: Weekday, hours: Vec<DayHour>) -> Self {
|
||||
Self {
|
||||
day,
|
||||
hours: DayHours(hours).to_string()
|
||||
}
|
||||
}
|
||||
pub fn day(&self) -> Weekday {
|
||||
self.day
|
||||
}
|
||||
pub fn hours(&self) -> &str {
|
||||
&self.hours
|
||||
}
|
||||
}
|
||||
|
||||
/*pub struct Property {
|
||||
id: u16,
|
||||
name: String,
|
||||
@@ -135,14 +310,6 @@ pub struct Message {
|
||||
text: String,
|
||||
}
|
||||
|
||||
pub struct OpeningHour {
|
||||
id: u16,
|
||||
day: Weekday,
|
||||
from: NaiveTime,
|
||||
to: NaiveTime,
|
||||
discount: u8
|
||||
}
|
||||
|
||||
pub struct Customer {
|
||||
id: u128,
|
||||
full_name: String,
|
||||
|
||||
@@ -4,6 +4,7 @@ pub mod data;
|
||||
pub mod company;
|
||||
pub mod user;
|
||||
pub mod auth_middleware;
|
||||
pub mod opening_hours;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! perm_check {
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
use std::collections::HashMap;
|
||||
use chrono::Weekday;
|
||||
use leptos::*;
|
||||
use validator::Validate;
|
||||
use crate::backend::data::{ApiResponse, DayHour, WeekHours};
|
||||
use crate::components::data_form::ForValidation;
|
||||
|
||||
#[server]
|
||||
pub async fn get_hours() -> Result<HashMap<Weekday, Vec<DayHour>>, ServerFnError> {
|
||||
use crate::backend::get_pool;
|
||||
use crate::backend::data::OpeningHour;
|
||||
|
||||
let pool = get_pool().await?;
|
||||
let hours = sqlx::query_as::<_, OpeningHour>("SELECT * FROM opening_hour").fetch_all(&pool).await?;
|
||||
|
||||
let mut ret: HashMap<Weekday, Vec<DayHour>> = hours.into_iter().fold(HashMap::new(), |mut map, v| {
|
||||
map.entry(Weekday::try_from(v.day as u8).unwrap_or(Weekday::Mon))
|
||||
.and_modify(|h| h.push(DayHour::new(v.from, v.to, v.discount)))
|
||||
.or_insert(vec![DayHour::new(v.from, v.to, v.discount)]);
|
||||
map
|
||||
});
|
||||
|
||||
for d in 0..6 {
|
||||
if let None = ret.get(&Weekday::try_from(d as u8).unwrap()) {
|
||||
ret.insert(Weekday::try_from(d as u8).unwrap(), Vec::new());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
#[server]
|
||||
pub async fn update_hours(hours: WeekHours) -> Result<ApiResponse<()>, ServerFnError> {
|
||||
use crate::perm_check;
|
||||
use crate::backend::get_pool;
|
||||
use crate::backend::data::DayHours;
|
||||
|
||||
perm_check!(is_admin);
|
||||
|
||||
let hr = DayHours::try_new(hours.hours())?;
|
||||
let pool = get_pool().await?;
|
||||
let day = hours.day();
|
||||
let mut tx = pool.begin().await?;
|
||||
|
||||
sqlx::query("DELETE FROM opening_hour WHERE day = $1")
|
||||
.bind(day.num_days_from_monday() as i32)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
for h in hr.hours() {
|
||||
sqlx::query(r#"INSERT INTO opening_hour(day, "from", "to", discount) VALUES($1, $2, $3, $4)"#)
|
||||
.bind(day.num_days_from_monday() as i32)
|
||||
.bind(h.from())
|
||||
.bind(h.to())
|
||||
.bind(h.discount())
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
}
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
Ok(ApiResponse::Data(()))
|
||||
}
|
||||
|
||||
impl ForValidation for UpdateHours {
|
||||
fn entity(&self) -> &dyn Validate {
|
||||
&self.hours
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
use std::error::Error;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum AppError {
|
||||
HourParseError
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
fn as_string(&self) -> String {
|
||||
//match self { AppError::HourParseError => {"Hour parse error"} }
|
||||
"Hours parse error".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AppError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.as_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for AppError {}
|
||||
@@ -4,6 +4,7 @@ pub mod backend;
|
||||
mod pages;
|
||||
mod components;
|
||||
mod validator;
|
||||
pub mod error;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
|
||||
|
||||
@@ -16,6 +16,15 @@ lazy_static! {
|
||||
("Name cannot be empty", "Jméno nesmí být prázdné"),
|
||||
("Invalid old password", "Neplatné staré heslo"),
|
||||
("Please sign-in to your account", "Přihlaste se prosím k uživatelskému účtu"),
|
||||
("Closed", "Zavřeno"),
|
||||
("Monday", "Pondělí"),
|
||||
("Tuesday", "Úterý"),
|
||||
("Wednesday", "Středa"),
|
||||
("Thursday", "Čtvrtek"),
|
||||
("Friday", "Pátek"),
|
||||
("Saturday", "Sobota"),
|
||||
("Sunday", "Neděle"),
|
||||
("Opening hours", "Otvírací hodiny"),
|
||||
])),
|
||||
("sk", HashMap::from( [
|
||||
("Dashboard", "Prehlad"),
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
use leptos::*;
|
||||
use crate::backend::data::WeekHours;
|
||||
use crate::backend::opening_hours::UpdateHours;
|
||||
use crate::components::data_form::DataForm;
|
||||
use crate::components::modal_box::DialogOpener;
|
||||
|
||||
#[component]
|
||||
pub fn EditHours(opener: DialogOpener, hours: ReadSignal<WeekHours>) -> impl IntoView {
|
||||
let update_hours = create_server_action::<UpdateHours>();
|
||||
|
||||
view! {
|
||||
<DataForm opener=opener action=update_hours title="Edit hours">
|
||||
<input type="hidden" value={move || hours.get().day().to_string()} name="hours[day]"/>
|
||||
<div class="row">
|
||||
<div class="col mb-3">
|
||||
<label for="hours" class="form-label">"Hours"</label>
|
||||
<input
|
||||
type="text"
|
||||
id="hours"
|
||||
class="form-control"
|
||||
placeholder="12:00 - 15:00, 17:00 - 21:00"
|
||||
prop:value={move || hours.get().hours().to_string()}
|
||||
name="hours[hours]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</DataForm>
|
||||
}
|
||||
}
|
||||
+7
-4
@@ -1,11 +1,14 @@
|
||||
pub mod home_page;
|
||||
pub mod settings;
|
||||
pub mod company_info;
|
||||
mod company_info;
|
||||
mod company_edit;
|
||||
pub mod login;
|
||||
pub mod public;
|
||||
pub mod profile_edit;
|
||||
pub mod change_pwd;
|
||||
pub mod users;
|
||||
pub mod user_edit;
|
||||
pub mod user_delete;
|
||||
mod users;
|
||||
mod user_edit;
|
||||
mod user_delete;
|
||||
mod opening_hours;
|
||||
mod hours_edit;
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
use chrono::Weekday;
|
||||
use leptos::*;
|
||||
use crate::backend::data::{DayHours, WeekHours};
|
||||
use crate::backend::opening_hours::get_hours;
|
||||
use crate::components::modal_box::DialogOpener;
|
||||
use crate::locales::trl;
|
||||
use crate::pages::hours_edit::EditHours;
|
||||
|
||||
fn show_time(tm: &str) -> impl Fn() -> String {
|
||||
if tm.is_empty() {
|
||||
trl("Closed")
|
||||
} else {
|
||||
trl(tm)
|
||||
}
|
||||
}
|
||||
|
||||
fn show_day(day: &Weekday) -> impl Fn() -> String {
|
||||
match day {
|
||||
Weekday::Mon => { trl("Monday") }
|
||||
Weekday::Tue => { trl("Tuesday") }
|
||||
Weekday::Wed => { trl("Wednesday") }
|
||||
Weekday::Thu => { trl("Thursday") }
|
||||
Weekday::Fri => { trl("Friday") }
|
||||
Weekday::Sat => { trl("Saturday") }
|
||||
Weekday::Sun => { trl("Sunday") }
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn OpeningHours() -> impl IntoView {
|
||||
let editor = DialogOpener::new();
|
||||
let hours = create_blocking_resource(move || editor.visible(), move |_| {get_hours()});
|
||||
let hrs = create_rw_signal(WeekHours::default());
|
||||
|
||||
view! {
|
||||
<EditHours opener=editor hours=hrs.read_only() />
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title"><i class="bx bxs-watch"></i>" "{trl("Opening hours")}</h5>
|
||||
<p class="card-text">
|
||||
<Transition fallback=move || view! {<p>{trl("Loading...")}</p> }>
|
||||
{move || {
|
||||
hours.get().map(|h| match h {
|
||||
Ok(h) => {
|
||||
let h = create_rw_signal(h);
|
||||
let d = create_rw_signal((0..7).collect::<Vec<u8>>());
|
||||
view! {
|
||||
<div>
|
||||
<table class="table card-table">
|
||||
<For each=move || d.get() key=|day| *day
|
||||
children=move |day| {
|
||||
let week_day = Weekday::try_from(day).unwrap_or(Weekday::Mon);
|
||||
let hr_c = h.get().get(&week_day).unwrap_or(&Vec::new()).clone();
|
||||
let hr_day = hr_c.clone();
|
||||
view! {
|
||||
<tr>
|
||||
<td>{show_day(&week_day)}</td>
|
||||
<td>{show_time(&DayHours(hr_day).to_string())}</td>
|
||||
<td><a href="javascript:void(0)" class="card-link" on:click = move |_| {
|
||||
hrs.set(WeekHours::new(week_day, hr_c.clone()));
|
||||
editor.show();
|
||||
}><i class="bx bx-edit-alt me-1"></i></a></td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
/>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
Err(e) => {view! {<div><p>{trl("Error loading data")}</p>
|
||||
<p>{e.to_string()}</p></div>
|
||||
}}
|
||||
})
|
||||
}}
|
||||
</Transition>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use leptos::*;
|
||||
use crate::locales::trl;
|
||||
use crate::pages::company_info::CompanyInfo;
|
||||
use crate::pages::opening_hours::OpeningHours;
|
||||
use crate::pages::users::Users;
|
||||
|
||||
#[component]
|
||||
@@ -15,5 +16,13 @@ pub fn Settings() -> impl IntoView {
|
||||
<Users/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-5">
|
||||
<div class="col-md">
|
||||
<OpeningHours/>
|
||||
</div>
|
||||
<div class="col-md">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user