This commit is contained in:
2021-10-29 18:42:04 +02:00
parent 4c689a9a9e
commit f2c470ed3d
19 changed files with 6097 additions and 744 deletions

1
api/.gitignore vendored
View File

@@ -1 +1,2 @@
/target/
/sqlite.db

74
api/Cargo.lock generated
View File

@@ -2,6 +2,17 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ahash"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
dependencies = [
"getrandom 0.2.3",
"once_cell",
"version_check",
]
[[package]]
name = "autocfg"
version = "1.0.1"
@@ -75,6 +86,18 @@ dependencies = [
"generic-array",
]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fallible-streaming-iterator"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
[[package]]
name = "fnv"
version = "1.0.7"
@@ -210,6 +233,18 @@ name = "hashbrown"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
dependencies = [
"ahash",
]
[[package]]
name = "hashlink"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
dependencies = [
"hashbrown",
]
[[package]]
name = "headers"
@@ -360,6 +395,16 @@ version = "0.2.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
[[package]]
name = "libsqlite3-sys"
version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abd5850c449b40bacb498b2bbdfaff648b1b055630073ba8db499caf2d0ea9f2"
dependencies = [
"pkg-config",
"vcpkg",
]
[[package]]
name = "lock_api"
version = "0.4.5"
@@ -481,6 +526,7 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
name = "packager-api"
version = "0.1.0"
dependencies = [
"rusqlite",
"serde",
"serde_json",
"tokio",
@@ -551,6 +597,12 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb"
[[package]]
name = "ppv-lite86"
version = "0.2.10"
@@ -680,6 +732,22 @@ dependencies = [
"winapi",
]
[[package]]
name = "rusqlite"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2aebd07fccf5c0d3f1458219965b0861d45f5db9f9b2617277fa7f85179213"
dependencies = [
"bitflags",
"fallible-iterator",
"fallible-streaming-iterator",
"hashlink",
"libsqlite3-sys",
"memchr",
"smallvec",
"uuid",
]
[[package]]
name = "ryu"
version = "1.0.5"
@@ -1035,6 +1103,12 @@ dependencies = [
"serde",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.3"

View File

@@ -4,22 +4,37 @@ version = "0.1.0"
authors = [
"Hannes Körber <hannes@hkoerber.de>"
]
edition = "2021"
edition = "2018"
readme = "README.md"
repository = "https://github.com/hkoerber/packager/"
license = "AGPL-3.0-only"
publish = false
[profile.release]
lto = true
[lib]
name = "packager"
[dependencies]
tokio = { version = "1", features = ["full"] }
warp = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "0.8", features = ["serde", "v4"] }
[dependencies.tokio]
version = "1"
features = ["full"]
[dependencies.serde]
version = "1.0"
features = ["derive"]
[dependencies.uuid]
version = "0.8"
features = ["serde", "v4"]
[dependencies.rusqlite]
version = "0.26.0"
features = ["uuid"]

1042
api/src/db.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,646 +1,53 @@
pub mod packagelist;
use uuid::Uuid;
pub mod packagelist;
pub use packagelist::Duration;
pub use packagelist::ItemSize;
pub use packagelist::ItemUsage;
pub use packagelist::PackageItem;
pub use packagelist::PackageList;
pub use packagelist::Period;
pub use packagelist::Preparation;
pub use packagelist::PreparationStep;
pub mod router;
pub mod db;
pub mod trip;
pub use trip::Trip;
pub use trip::TripList;
pub use trip::TripParameters;
pub use trip::TripState;
pub fn get_list(id: Uuid) -> Option<packagelist::PackageList> {
println!("Looking for id {}", id);
for list in get_lists() {
println!("Have {}", list.id);
if list.id == id {
println!("Found!");
return Some(list);
}
}
println!("Not Found!");
None
}
pub fn get_trips() -> Vec<Trip> {
let package_lists = get_lists();
vec![
Trip::from_package_list(
Uuid::parse_str("98dd50f9-b945-48e0-8fa9-41a3fd8b897e").unwrap(),
String::from("Campingtrip"),
String::from("2021-09-06"),
vec![
package_lists[0].id,
package_lists[1].id,
],
)
]
self::db::get_list(id).unwrap()
}
pub fn get_lists() -> Vec<packagelist::PackageList> {
vec![
packagelist::PackageList::new_from_items(
Uuid::parse_str("5f95d8c7-c4da-44bc-af30-2d10c479de8a").unwrap(),
String::from("EDC"),
vec![
packagelist::PackageItem::new_simple(
Uuid::parse_str("48703b81-037a-401f-8f46-56c242bb16c3").unwrap(),
String::from("Rucksack"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("39b26f98-0cbc-46d5-ac17-43d61ba1a503").unwrap(),
String::from("Regenhülle für Rucksack"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("a5934361-bc5d-4092-bad4-95c15c875dca").unwrap(),
String::from("Normale Schuhe"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("4b0a6dbb-652b-464a-b413-93dd4f010ce3").unwrap(),
String::from("Taschenmesser"),
),
packagelist::PackageItem::new(
Uuid::parse_str("9823e841-64d1-43ab-a05f-95606b89482c").unwrap(),
String::from("Taschentücher"),
packagelist::ItemSize::Pack(1),
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("a7eac657-e870-4181-a644-16fe229d917a").unwrap(),
String::from("Handy"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::Steps(vec![packagelist::PreparationStep::new(
String::from("Aufladen"),
packagelist::Duration::Days(1),
)]),
),
packagelist::PackageItem::new(
Uuid::parse_str("c0d97e46-a9fe-4d20-a3e9-8cf7c69d2fbf").unwrap(),
String::from("Kopfhörer"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::Steps(vec![packagelist::PreparationStep::new(
String::from("Aufladen"),
packagelist::Duration::Days(1),
)]),
),
packagelist::PackageItem::new(
Uuid::parse_str("9b04e117-1a61-4643-8238-55c401a2dd00").unwrap(),
String::from("Mundschutz"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Weekly(1)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("5efe30c7-896d-4c32-9976-81ac93ff6aa0").unwrap(),
String::from("Kokain"),
packagelist::ItemSize::Gram(100),
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Weekly(1)),
packagelist::Preparation::Steps(vec![packagelist::PreparationStep::new(
String::from("Beim Dealer kaufen"),
packagelist::Duration::Days(1),
)]),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("8fb8d7ce-7766-4203-bc38-058fe2440519").unwrap(),
String::from("Ladekabel"),
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("3ea0714e-3115-46c4-8ae0-f2a37398cc7a").unwrap(),
String::from("Geld & Karten"),
vec![
packagelist::PackageItem::new(
Uuid::parse_str("18ebb1bc-e01f-4dc7-bda7-919dd8f069c7").unwrap(),
String::from("Bargeld"),
packagelist::ItemSize::Name(String::from("Euro")),
100,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::Steps(vec![packagelist::PreparationStep::new(
String::from("Abheben"),
packagelist::Duration::Days(1),
)]),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("2aba4c22-9c3d-4b19-95b5-265f1846b8f9").unwrap(),
String::from("Kreditkarte"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("aeec841e-0691-4af9-b719-16a6752c33d6").unwrap(),
String::from("Pass"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("1a598c16-a238-4d02-baef-03208beb9509").unwrap(),
String::from("Krankenversicherungskarte"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("584955e2-3bf4-459c-8c87-631414842571").unwrap(),
String::from("Krankenversicherungskarte (Zusatz)"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("571dd7b6-0420-4f8f-8e83-fb430c6f1c23").unwrap(),
String::from("Auslandskrankenversicherungsnachweis"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("25937e62-4ade-495b-9535-c4db1176fbab").unwrap(),
String::from("Notfalltelefonnummernliste"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("6464f872-00f6-4621-9d37-ff6b75c8d79a").unwrap(),
String::from("ADAC-Karte"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("0b9298b7-6bdb-4fdc-a171-1953654b160e").unwrap(),
String::from("Impfausweiß (EU)"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("fac04399-e092-4aeb-bf61-edd081890fa6").unwrap(),
String::from("Führerschein"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("17ef3d3a-010f-44c1-acae-ef0ea9a985b8").unwrap(),
String::from("Internationaler Führerschein"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("b256cd9f-8c5c-45f2-9e08-04cc62800cfe").unwrap(),
String::from("Tagebuch"),
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("4b2c2d4e-3014-48aa-95e0-39f352cb6494").unwrap(),
String::from("Waschzeug"),
vec![
packagelist::PackageItem::new_simple(
Uuid::parse_str("c91e2295-7fa6-4165-bb6c-0de60069c410").unwrap(),
String::from("Waschbeutel"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("005639bb-b336-4e7c-bb88-aeaca20fc488").unwrap(),
String::from("Sonnencreme"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("9a907ab6-3e49-4cc0-af86-637821127354").unwrap(),
String::from("After-Sun"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("7ed5be40-929e-4ae2-a723-61e6514e9592").unwrap(),
String::from("Nagelset"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("40f9bc11-1e24-4a60-b183-7f9a2eab0e42").unwrap(),
String::from("Rasurbox"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("c72126c8-5639-4952-b4a7-d588d636a6f0").unwrap(),
String::from("Rasierer"),
),
packagelist::PackageItem::new(
Uuid::parse_str("9f6e9c09-e550-411c-a89d-7f79608b1bb6").unwrap(),
String::from("Ersatzklingen"),
packagelist::ItemSize::Pack(1),
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::None,
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("547fb1cd-568b-44d2-9618-0f4de7ca2ca5").unwrap(),
String::from("Zahnbürste"),
),
packagelist::PackageItem::new(
Uuid::parse_str("09259ebe-407b-4808-9a19-db3b95f77846").unwrap(),
String::from("Zahnputztabletten"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Daily(2)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("10342277-9984-4c9a-ad07-155e148f91fd").unwrap(),
String::from("Deo"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("e323ca57-8487-4b3f-a3f9-6dd8e26ff0e4").unwrap(),
String::from("Duschgel / Shampoo"),
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("4ba0462f-5c75-4926-9ca2-ea93ef5b66ef").unwrap(),
String::from("Apotheke"),
vec![
packagelist::PackageItem::new(
Uuid::parse_str("bdeea898-479b-41e9-8d33-1c79743b3011").unwrap(),
String::from("Blasenpflaster"),
packagelist::ItemSize::Pack(1),
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("2175fa92-0ef2-48a1-bea0-f70268b0ad68").unwrap(),
String::from("Erste-Hilfe-Set"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("bad9f320-eaf8-4240-bfa6-890b755eb03a").unwrap(),
String::from("Paracetamol"),
packagelist::ItemSize::Pack(1),
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("b9d3f29d-4448-42ba-aeff-ba179542b4ae").unwrap(),
String::from("Autan"),
packagelist::ItemSize::Pack(1),
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("bfeb6d0f-5122-4f80-94e9-be54a1d1c838").unwrap(),
String::from("Pflaster"),
packagelist::ItemSize::Pack(1),
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("3f08c3e2-a0d9-40fb-b3fb-f4bb79815b9d").unwrap(),
String::from("Zeckenkarte"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("9aa4ee9f-2f00-42d2-980e-8fd1ede0283c").unwrap(),
String::from("Badesachen"),
vec![
packagelist::PackageItem::new_simple(
Uuid::parse_str("879b9d32-0de5-45f3-bffb-0c1e73b5a7b8").unwrap(),
String::from("Badehose"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("5610ab1f-308d-4ef9-b8e4-3721fa4c4172").unwrap(),
String::from("Badehandtuch"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("e7e3c053-a269-4f0d-b6bd-99b48bf4573a").unwrap(),
String::from("Surfshirt (Lang)"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("360c20f5-8142-48d1-add4-a8f2a48a242b").unwrap(),
String::from("Wasserschuhe"),
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("1e0728d1-9dd9-48ff-a206-a73b604b9748").unwrap(),
String::from("Camping"),
vec![
packagelist::PackageItem::new_simple(
Uuid::parse_str("fb6eec8c-a1ad-420f-b8de-9695e9ccb67d").unwrap(),
String::from("Schlafsack"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("69a06abd-34f4-4991-9a41-b3ec50bcbbd7").unwrap(),
String::from("Zelt"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("22169568-1976-43ab-8c40-37c7e6193e18").unwrap(),
String::from("Luftmatratze"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("dd10738b-0162-4e0a-9db9-ea5e16ee5566").unwrap(),
String::from("Campingstuhl"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("a88c14c1-8194-4fea-be6c-b532517bbf97").unwrap(),
String::from("Panzertape"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("fb67fbf1-cd04-4b39-b0a3-bff4bf07f38e").unwrap(),
String::from("Tarp"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("6de5825b-0e39-4693-9664-2edc7353db3b").unwrap(),
String::from("Hängematte"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("c6f14fb7-c598-4a47-8b12-b96ff3856a21").unwrap(),
String::from("Topf"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("2fb43b9c-c6ca-4fda-9e09-e1a83efdc4f7").unwrap(),
String::from("Teller"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("a203f34c-e912-4479-ad8e-e16150122cad").unwrap(),
String::from("Messer"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("63837c0a-7a8e-40ae-aced-818066bd9e89").unwrap(),
String::from("Gabel"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("437a45d9-4fc5-459e-b790-7628945d7c38").unwrap(),
String::from("Löffel"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("a461859f-b430-42da-bf52-8cdb3eb42d13").unwrap(),
String::from("Stirnlampe"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("f109c12f-10dd-4249-a02e-c28aaa20a8f6").unwrap(),
String::from("Geschirrtuch"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("1f2ffc7e-060a-4277-a15d-119b85481438").unwrap(),
String::from("Spüllappen"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("bf6d49fe-25cc-4114-a374-3c4772cf5f3a").unwrap(),
String::from("Taschenlampe"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("03994e35-f0f0-4ccd-bc24-0a331ffbba96").unwrap(),
String::from("Feuerzeug"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("fc3ecdab-eb3a-4d27-8f95-cd78d37e063e").unwrap(),
String::from("Tasse"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("8b55efae-6e18-4d7f-a5b7-83ba15c50995").unwrap(),
String::from("Grill"),
),
packagelist::PackageItem::new(
Uuid::parse_str("b6d821e5-3285-4bf2-bd71-be9154f94937").unwrap(),
String::from("Grillkohle"),
packagelist::ItemSize::Gram(1500),
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Days(2)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("d2338ac1-9995-4319-8ca5-12654a266266").unwrap(),
String::from("Campingkocher"),
),
packagelist::PackageItem::new(
Uuid::parse_str("4ff62940-f691-4982-b1fd-54a2850e06f4").unwrap(),
String::from("Campinggas"),
packagelist::ItemSize::Pack(1),
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Days(3)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("a024c67a-6e61-4749-b2a4-1ec8ca132184").unwrap(),
String::from("Kaffeekochaufsatz"),
),
packagelist::PackageItem::new(
Uuid::parse_str("054e1610-1e8e-421e-95ad-c76e88cb45ab").unwrap(),
String::from("Küchenrolle"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Days(5)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("181310a8-946c-4075-9f95-c7a82d0269fd").unwrap(),
String::from("Müllsäcke"),
packagelist::ItemSize::Pack(1),
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("c823ce3f-922e-4300-95ad-21ff221cd896").unwrap(),
String::from("Teelichter"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Daily(3)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("e86bfb7c-a840-4b88-b216-afd3c173754b").unwrap(),
String::from("Klopapier"),
packagelist::ItemSize::Name(String::from("Rolle")),
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Weekly(1)),
packagelist::Preparation::None,
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("e5ecb3cc-a893-44cd-b4f8-4b41af003c96").unwrap(),
String::from("Essen"),
vec![packagelist::PackageItem::new(
Uuid::parse_str("6ebf5d87-6b97-4d80-8e03-25fa62e641d9").unwrap(),
String::from("Kaffee"),
packagelist::ItemSize::Gram(100),
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Days(3)),
packagelist::Preparation::None,
)],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("4e9042db-1db8-4912-8179-d0a3ebb80876").unwrap(),
String::from("Wanderzeug"),
vec![
packagelist::PackageItem::new_simple(
Uuid::parse_str("2eccd528-17a7-429f-b97a-70faae1b4dac").unwrap(),
String::from("Wanderschuhe"),
),
packagelist::PackageItem::new(
Uuid::parse_str("d8c52786-d50e-4a9f-b8c6-e9396c5be789").unwrap(),
String::from("Trinkblase"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::Steps(vec![packagelist::PreparationStep::new(
String::from("Auffüllen"),
packagelist::Duration::None,
)]),
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("5b272c8e-bf54-4af6-94e0-63071c92a8e3").unwrap(),
String::from("Klamotten"),
vec![
packagelist::PackageItem::new(
Uuid::parse_str("d18215d2-9cf9-48c7-894b-b9680ba39879").unwrap(),
String::from("Cap"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("83c03986-cc34-4500-9cee-1cc1778f5cf3").unwrap(),
String::from("Regenjacke"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("00c116ba-840d-47c4-a081-5e256941d3b9").unwrap(),
String::from("Daunenjacke"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("35834bec-6c63-41df-825c-05b943e07bc8").unwrap(),
String::from("Pullover"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("127704a8-1e4d-4c49-b74f-34130ed08f83").unwrap(),
String::from("Lange Hose"),
packagelist::ItemSize::None,
2,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("e15a6772-3d5d-454d-8f7d-bf9066ba5d23").unwrap(),
String::from("Kurze Hose"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("09992e6d-408a-43e4-beee-1925e727415f").unwrap(),
String::from("Jogginghose"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("799f0fd4-2be7-44b5-b286-889242900be3").unwrap(),
String::from("Socken"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Daily(1)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("f57f3299-a46a-4ed3-aff0-ffc5d2627a6a").unwrap(),
String::from("Unterhose"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Daily(1)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("c100f7be-ceb7-46a6-aded-380a201bfe45").unwrap(),
String::from("T-Shirt"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Days(2)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("22908312-a8d2-4005-893c-12e56d9af022").unwrap(),
String::from("Schmutzwäschebeutel"),
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("929bc029-ec8f-4294-9484-ec32f0170f5c").unwrap(),
String::from("Fahrrad"),
vec![
packagelist::PackageItem::new_simple(
Uuid::parse_str("d91ed4fd-ef9b-4ad5-849f-1481dbbc95b0").unwrap(),
String::from("Fahrrad"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("2f2a09d7-2d97-4ff8-9fb1-ace86eaf6de5").unwrap(),
String::from("Fahrradhelm"),
),
],
),
packagelist::PackageList::new_from_items(
Uuid::parse_str("0103e348-b4e8-4cc9-95e6-4ef85b7c76ab").unwrap(),
String::from("Misc"),
vec![
packagelist::PackageItem::new_simple(
Uuid::parse_str("990c7121-7342-48a2-9abb-4d0e274b6759").unwrap(),
String::from("Trinkflasche"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("0ead2b93-9b81-4e32-a856-0a562557598c").unwrap(),
String::from("Dyneemaschnur"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("be5d49bc-9c06-4747-b954-9ca003694018").unwrap(),
String::from("Ladegerät"),
),
packagelist::PackageItem::new(
Uuid::parse_str("aab7b03b-19f9-4149-a23d-3c14d938cca4").unwrap(),
String::from("Powerbank"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Infinite,
packagelist::Preparation::Steps(vec![packagelist::PreparationStep::new(
String::from("Aufladen"),
packagelist::Duration::Days(1),
)]),
),
packagelist::PackageItem::new(
Uuid::parse_str("c54deb17-fe62-4300-8297-c5dfc4773a02").unwrap(),
String::from("Desinfektionsgel"),
packagelist::ItemSize::None,
1,
packagelist::ItemUsage::Periodic(packagelist::Period::Weekly(1)),
packagelist::Preparation::None,
),
packagelist::PackageItem::new(
Uuid::parse_str("3fb87c86-7155-4df5-8f7b-68c288ba1147").unwrap(),
String::from("Karabiner"),
packagelist::ItemSize::None,
3,
packagelist::ItemUsage::Singleton,
packagelist::Preparation::None,
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("c965176c-9014-4e8f-8e99-8cd2e37a64ac").unwrap(),
String::from("Ersatzbrille"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("b0909ce6-5a8c-42fa-a384-de108f19ee5d").unwrap(),
String::from("Sonnenbrille"),
),
packagelist::PackageItem::new_simple(
Uuid::parse_str("7ec347d4-0c28-48bb-9c32-558a1988a164").unwrap(),
String::from("Ohrenstöpsel"),
),
],
),
]
self::db::get_lists().unwrap()
}
pub fn get_packagelist_items(id: Uuid) -> Vec<packagelist::PackageItem> {
self::db::get_list_items(id).unwrap()
}
pub fn get_preparation(list_id: Uuid, item_id: Uuid) -> Vec<packagelist::PreparationStep> {
self::db::get_preparation(list_id, item_id).unwrap()
}
pub fn new_item(list_id: Uuid, item_name: String, item_count: i32) -> packagelist::PackageItem {
let item = PackageItem::new(
Uuid::new_v4(),
item_name,
ItemSize::None,
item_count,
ItemUsage::Singleton,
Preparation::None,
);
self::db::save_item(list_id, item).unwrap()
}
pub fn get_trips() -> Vec<Trip> {
self::db::get_trips().unwrap()
}

View File

@@ -1,4 +1,4 @@
use packager;
use std::env;
#[tokio::main]
async fn main() {
@@ -32,7 +32,19 @@ async fn main() {
// for item in &trip.list.items {
// println!("{:?}", item);
// }
let args: Vec<String> = env::args().skip(1).collect();
match args.get(0) {
None => (),
Some(cmd) => match cmd.as_ref() {
"--load-example-data" => {
packager::db::load().unwrap();
}
_ => panic!("Unknown argument: \"{}\"", cmd),
},
};
let router = packager::router::new();
println!("Initialization done, listening for connections");
warp::serve(router).run(([127, 0, 0, 1], 9000)).await;
}

View File

@@ -1,5 +1,5 @@
use serde::ser::{SerializeStruct, Serializer};
use serde::{Serialize};
use serde::Serialize;
use uuid::Uuid;
@@ -134,20 +134,20 @@ impl ItemSize {
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PreparationStep {
name: String,
pub id: Uuid,
pub name: String,
#[serde(skip_serializing_if = "Duration::is_none")]
start: Duration,
pub start: Duration,
}
impl PreparationStep {
pub fn new(name: String, start: Duration) -> PreparationStep {
PreparationStep { name, start }
pub fn new(id: Uuid, name: String, start: Duration) -> PreparationStep {
PreparationStep { id, name, start }
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
#[derive(Debug)]
pub enum Preparation {
None,
Steps(Vec<PreparationStep>),
@@ -159,19 +159,38 @@ impl Preparation {
}
}
impl Serialize for Preparation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Preparation::None => {
// serializer.serialize_unit_variant("Preparation", 0, "null")
let steps: Vec<i32> = vec![];
serializer.serialize_newtype_variant("Preparation", 1, "steps", &steps)
// let mut s = serializer.serialize_seq(Some(0))?;
// s.end()
}
Preparation::Steps(steps) => {
serializer.serialize_newtype_variant("Preparation", 1, "steps", steps)
}
}
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct PackageItem {
pub id: Uuid,
name: String,
pub name: String,
#[serde(skip_serializing_if = "ItemSize::is_none")]
size: ItemSize,
count: i32,
pub count: i32,
usage: ItemUsage,
#[serde(skip_serializing_if = "Preparation::is_none")]
preparation: Preparation,
pub preparation: Preparation,
}
impl PackageItem {
@@ -217,4 +236,16 @@ impl PackageList {
pub fn new_from_items(id: Uuid, name: String, items: Vec<PackageItem>) -> PackageList {
PackageList { id, name, items }
}
pub fn new(id: Uuid, name: String) -> PackageList {
PackageList {
id,
name,
items: Vec::new(),
}
}
pub fn set_items(&mut self, items: Vec<PackageItem>) {
self.items = items;
}
}

View File

@@ -1,4 +1,4 @@
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::convert::Infallible;
use warp;
@@ -19,9 +19,28 @@ struct ErrorMessage {
message: String,
}
#[derive(Deserialize, Clone)]
#[serde(deny_unknown_fields)]
struct JsonListItem {
name: String,
count: i32,
}
pub fn new() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
let accept_json = warp::header::exact("accept", "application/json");
let cors = warp::cors().allow_any_origin();
let content_json = warp::header::exact("content-type", "application/json");
let cors = warp::cors()
.allow_any_origin()
.allow_methods(&[
warp::http::Method::GET,
warp::http::Method::POST,
warp::http::Method::DELETE,
])
.allow_headers(vec!["accept", "content-type"]);
fn json_body() -> impl Filter<Extract = (JsonListItem,), Error = warp::Rejection> + Clone {
warp::body::content_length_limit(1024 * 16).and(warp::body::json())
}
let root = warp::path::end().map(|| "Hi");
@@ -55,6 +74,56 @@ pub fn new() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
})
.with(&cors);
let list_items = warp::path!("v1" / "lists" / String / "items")
.and(warp::path::end())
.and(warp::get())
.and(accept_json)
.and_then(|list_id: String| async move {
match Uuid::parse_str(&list_id) {
Ok(uuid) => {
let items = &super::get_packagelist_items(uuid);
Ok(warp::reply::json(items))
}
Err(_) => Err(warp::reject::custom(InvalidUuid)),
}
})
.with(&cors);
let preparation = warp::path!("v1" / "lists" / String / "items" / String / "preparation")
.and(warp::path::end())
.and(warp::get())
.and(accept_json)
.and_then(|list_id: String, item_id: String| async move {
match Uuid::parse_str(&list_id) {
Ok(list_id) => match Uuid::parse_str(&item_id) {
Err(_) => Err(warp::reject::custom(InvalidUuid)),
Ok(item_id) => {
let items = &super::get_preparation(list_id, item_id);
Ok(warp::reply::json(items))
}
},
Err(_) => Err(warp::reject::custom(InvalidUuid)),
}
})
.with(&cors);
let new_item = warp::path!("v1" / "lists" / String / "items")
.and(warp::path::end())
.and(warp::post())
.and(accept_json)
.and(content_json)
.and(json_body())
.and_then(|list_id: String, item: JsonListItem| async move {
match Uuid::parse_str(&list_id) {
Ok(list_id) => {
let new_item = &super::new_item(list_id, item.name, item.count);
Ok(warp::reply::json(new_item))
}
Err(_) => Err(warp::reject::custom(InvalidUuid)),
}
})
.with(&cors);
let trips = warp::path!("v1" / "trips")
.and(warp::path::end())
.and(warp::get())
@@ -65,6 +134,9 @@ pub fn new() -> warp::filters::BoxedFilter<(impl warp::Reply,)> {
root.or(v1)
.or(lists)
.or(list)
.or(new_item)
.or(list_items)
.or(preparation)
.or(trips)
.recover(handle_rejection)
.boxed()
@@ -81,10 +153,10 @@ async fn handle_rejection(err: warp::Rejection) -> Result<impl warp::Reply, Infa
} else if let Some(InvalidUuid) = err.find() {
code = StatusCode::BAD_REQUEST;
message = "INVALID_UUID";
} else if let Some(_) = err.find::<warp::filters::body::BodyDeserializeError>() {
} else if err.find::<warp::filters::body::BodyDeserializeError>().is_some() {
message = "BAD_REQUEST";
code = StatusCode::BAD_REQUEST;
} else if let Some(_) = err.find::<warp::reject::MethodNotAllowed>() {
} else if err.find::<warp::reject::MethodNotAllowed>().is_some() {
message = "METHOD_NOT_ALLOWED";
code = StatusCode::METHOD_NOT_ALLOWED;
} else {

View File

@@ -1,5 +1,5 @@
use serde::Serialize;
use uuid::Uuid;
use serde::{Serialize};
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
@@ -11,42 +11,63 @@ pub enum TripItemStatus {
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TripItem<'a> {
pub id: Uuid,
pub package_item: &'a super::PackageItem,
pub status: TripItemStatus,
pub struct TripParameters {
pub days: i32,
}
impl TripItem<'_> {
pub fn from_package_item(id: Uuid, package_item: &super::PackageItem) -> TripItem {
TripItem {
id,
package_item,
status: TripItemStatus::Pending,
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TripPackageList {
pub id: Uuid,
pub name: String,
}
impl TripPackageList {
fn construct(item: (Uuid, String)) -> TripPackageList {
TripPackageList {
id: item.0,
name: item.1,
}
}
pub fn set_status(&mut self, status: TripItemStatus) {
self.status = status;
fn construct_vec(items: Vec<(Uuid, String)>) -> Vec<TripPackageList> {
items
.into_iter()
.map(TripPackageList::construct)
.collect()
}
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TripList<'a> {
pub id: Uuid,
pub items: Vec<TripItem<'a>>,
pub enum TripState {
Planned,
Packing,
Active,
Finished,
}
impl<'a> TripList<'a> {
pub fn from_package_list(id: Uuid, list: &'a super::PackageList) -> TripList<'a> {
let mut items = Vec::new();
for item in &list.items {
items.push(TripItem::from_package_item(Uuid::new_v4(), item));
impl rusqlite::types::FromSql for TripState {
fn column_result(value: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult<Self> {
match value.as_i64()? {
1 => Ok(TripState::Planned),
2 => Ok(TripState::Packing),
3 => Ok(TripState::Active),
4 => Ok(TripState::Finished),
v => Err(rusqlite::types::FromSqlError::OutOfRange(v)),
}
}
}
TripList { id, items }
impl rusqlite::types::ToSql for TripState {
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
let v = rusqlite::types::Value::Integer(match self {
TripState::Planned => 1,
TripState::Packing => 2,
TripState::Active => 3,
TripState::Finished => 4,
});
rusqlite::Result::Ok(rusqlite::types::ToSqlOutput::Owned(v))
}
}
@@ -56,21 +77,50 @@ pub struct Trip {
pub id: Uuid,
pub name: String,
pub date: String,
pub package_list_ids: Vec<Uuid>,
pub parameters: TripParameters,
pub package_lists: Vec<TripPackageList>,
pub state: TripState,
}
impl Trip {
pub fn from_package_list(
pub fn new(
id: Uuid,
name: String,
date: String,
package_list_ids: Vec<Uuid>,
parameters: TripParameters,
state: TripState,
) -> Trip {
Trip {
id,
name,
date,
package_list_ids,
parameters,
package_lists: vec![],
state,
}
}
pub fn from_package_list(
id: Uuid,
name: String,
date: String,
parameters: TripParameters,
package_lists: Vec<(Uuid, String)>,
state: TripState,
) -> Trip {
let lists = TripPackageList::construct_vec(package_lists);
Trip {
id,
name,
date,
parameters,
package_lists: lists,
state,
}
}
pub fn set_package_lists(&mut self, package_lists: Vec<(Uuid, String)>) {
let v = TripPackageList::construct_vec(package_lists);
self.package_lists = v;
}
}

4400
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,9 @@
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"@rollup/plugin-typescript": "^8.0.0",
"@tsconfig/svelte": "^2.0.0",
"npm": "^8.0.0",
"rollup": "^2.3.4",
"rollup-plugin-css-only": "^3.1.0",
"rollup-plugin-livereload": "^2.0.0",
@@ -19,10 +22,8 @@
"svelte": "^3.0.0",
"svelte-check": "^2.0.0",
"svelte-preprocess": "^4.0.0",
"@rollup/plugin-typescript": "^8.0.0",
"typescript": "^4.0.0",
"tslib": "^2.0.0",
"@tsconfig/svelte": "^2.0.0"
"typescript": "^4.0.0"
},
"dependencies": {
"sirv-cli": "^1.0.0"

View File

@@ -6,6 +6,8 @@
import Home from "./routes/Home.svelte";
import PackageLists from "./routes/PackageLists.svelte";
import PackageList from "./routes/PackageList.svelte";
import Preparation from "./routes/Preparation.svelte";
import Trips from "./routes/Trips.svelte";
function normalize(path) {
return path.replace(/\/+$/, '') + "/";
@@ -27,10 +29,20 @@
} else if (urlParts[0] == "lists" && urlParts.length == 1) {
console.log("=> PackageLists");
currentRoute = PackageLists;
} else if (urlParts[0] == "trips" && urlParts.length == 1) {
console.log("=> Trips");
currentRoute = Trips;
} else if (urlParts[0] == "lists" && urlParts.length == 2) {
console.log("=> PackageList");
currentRoute = PackageList;
data = {id: urlParts[1]};
} else if (urlParts.length == 5
&& urlParts[0] == "lists"
&& urlParts[2] == "items"
&& urlParts[4] == "preparation") {
console.log("=> PackageList");
currentRoute = Preparation;
data = {list_id: urlParts[1], item_id: urlParts[3]};
} else {
console.log("No matching route found");
}

View File

@@ -2,9 +2,9 @@
export let data;
</script>
<main>
<div>
{data.name}
</main>
</div>
<style>
</style>

View File

@@ -1,11 +1,22 @@
<script lang="ts">
export let list;
export let id;
export let items;
export let redirect;
$: has_sizes = list.items.some(l => l.size.type != "None");
$: has_counts = list.items.some(l => l.count > 1);
$: has_counts = items.some(l => l.count > 1);
$: has_preparations = items.some(l => l.preparation.steps.length > 0);
//has_sizes = items.some(l => l.size.type != "None");
let has_sizes = false;
let has_preparations = false;
let has_counts = false;
const navigateToPreparation = (item_id) => {
redirect(`/lists/${id}/items/${item_id}/preparation`);
}
</script>
<main>
<div>
<table class="table-auto w-full">
<thead>
<tr class="font-semibold tracking-wider text-left bg-gray-100 uppercase border-b border-gray-400">
@@ -16,10 +27,13 @@
{#if has_counts}
<th class="p-3">Count</th>
{/if}
{#if has_preparations}
<th class="p-3">Preparation Steps</th>
{/if}
</tr>
</thead>
<tbody>
{#each list.items as item}
{#each items as item}
<tr class="border">
<td class="p-3">{item.name}</td>
{#if has_sizes }
@@ -49,8 +63,16 @@
{/if}
</td>
{/if}
{#if has_preparations}
<td class="p-3">
{#if item.preparation.steps.length > 0}
{item.preparation.steps.length} steps
<button on:click={() => navigateToPreparation(item.id)}>Show preparation steps</button>
{/if}
</td>
{/if}
</tr>
{/each}
</tbody>
</table>
</main>
</div>

View File

@@ -11,4 +11,5 @@
Welcome to Packager, your helper for your next trip!
</div>
<button on:click={navigateToPackageLists}>Lists</button>
<button on:click={() => redirect("/trips/")}>Trips</button>
</main>

View File

@@ -1,35 +1,134 @@
<script lang="ts">
import { onMount } from 'svelte';
import PackageListTable from "../components/PackageListTable.svelte"
export let redirect;
export let data;
const resetActiveElement = () => {
activeElement = {
name: "",
count: 1,
preparationsteps: [],
};
};
let activeElement;
resetActiveElement();
export const url = `/lists/${data.id}`
async function getList() {
let response = await fetch(`http://localhost:9000/v1/lists/${data.id}`, {
let sidebarActive = true;
const toggleSidebar = () => {
sidebarActive = !sidebarActive;
}
const apply = async () => {
const response = await fetch(`http://localhost:9000/v1/lists/${data.id}/items`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
},
body: JSON.stringify({
name: activeElement.name,
count: activeElement.count,
}),
cache: "no-store",
});
const d = await response.json();
console.log(d);
items = [...items, d];
console.log(items[0]);
console.log(d);
resetActiveElement();
sidebarActive = false;
}
const cancel = () => {
resetActiveElement();
sidebarActive = false;
}
async function getItems(id) {
let response = await fetch(`http://localhost:9000/v1/lists/${id}/items`, {
method: "GET",
headers: {
"Accept": "application/json"
},
cache: "no-store",
});
let list = await response.json();
return list;
items = await response.json();
}
async function getList() {
const response = await fetch(`http://localhost:9000/v1/lists/${data.id}`, {
method: "GET",
headers: {
"Accept": "application/json"
},
cache: "no-store",
})
list = await response.json();
}
let list = {name: ""};
let items = [];
onMount(async () => {
await getList();
await getItems(data.id);
});
</script>
<main>
<div>
{#await getList()}
<p>Loading</p>
{:then list}
<div class="container mx-auto">
<h2 class="text-3xl mt-12 mb-20 font-semibold text-center mb-5 mt-3">{list.name}</h2>
<PackageListTable list={list} />
<div class="container mx-auto grid grid-cols-12 gap-1 items-start justify-items-stretch">
<div class="col-start-1 col-end-9">
<PackageListTable items={items} id={list.id} {redirect}/>
<button class="p-3 w-full mt-3 border border-gray-200 bg-indigo-300" on:click={toggleSidebar}>Add new item</button>
</div>
<div class="col-start-9 col-end-10"/>
<div class="col-start-10 col-end-13">
{#if sidebarActive}
<div>
<label for="name">Name</label>
<input
class="w-full"
type="text"
id="name"
name="name"
bind:value={activeElement.name}
/>
</div>
<div>
<label for="count">Count</label>
<input
class="w-full"
type="number"
id="count"
name="count"
bind:value={activeElement.count}
/>
</div>
<div>
{#each activeElement.preparationsteps as step}
{step}
{/each}
</div>
<div class="flex flex-row mt-6 justify-between w-full">
<button type="submit" class="p-3 border border-gray-200 bg-green-300" on:click={() => apply()}>Apply</button>
<button class="p-3 border border-gray-200 bg-red-300" on:click={() => cancel()}>Cancel</button>
</div>
{/if}
</div>
</div>
{:catch error}
<p>Error: {error}</p>
{/await}
</div>
</main>

View File

@@ -20,19 +20,28 @@
</script>
<main>
<div>
<div class="container mx-auto mt-12">
<table class="table-auto w-full">
<thead>
<tr class="font-semibold tracking-wider text-left bg-gray-100 uppercase border-b border-gray-400">
<th class="p-3">Name</th>
<th class="p-3"># Items</th>
</tr>
</thead>
<tbody>
{#await getLists()}
<p>Loading</p>
{:then lists}
<div class="m-2 grid grid-cols-3 gap-5 items-start grid-flow-row">
{#each lists as list}
<div class="p-3 border rounded-lg border-gray-300 shadow hover:shadow-xl bg-gray-100 bg-opacity-30 hover:bg-opacity-100">
<PackageList id={list.id} name={list.name} items={list.items} on:select={e => redirect(url + e.detail.id)} />
</div>
<tr class="border" on:click={e => redirect(url + list.id)}>
<td class="p-3">{list.name}</td>
<td class="p-3">{list.items.length}</td>
</tr>
{/each}
</div>
{:catch error}
<p>Something went wrong</p>
<p>Error: {error}</p>
{/await}
</tbody>
</table>
</div>
</main>

View File

@@ -0,0 +1,41 @@
<script lang="ts">
export let redirect;
export let data;
async function getSteps() {
let response = await fetch(`http://localhost:9000/v1/lists/${data.list_id}/items/${data.item_id}/preparation`, {
method: "GET",
headers: {
"Accept": "application/json"
},
cache: "no-store",
});
let list = await response.json();
return list;
}
</script>
<main>
<table class="table-auto w-full">
<thead>
<tr class="font-semibold tracking-wider text-left bg-gray-100 uppercase border-b border-gray-400">
<th class="p-3">Name</th>
<th class="p-3">Start</th>
</tr>
</thead>
<tbody>
{#await getSteps()}
<p>Loading</p>
{:then steps}
{#each steps as step}
<tr class="border">
<td class="p-3">{step.name}</td>
<td class="p-3">{step.start.days} days before</td>
</tr>
{/each}
{:catch error}
<p>Error: {error}</p>
{/await}
</tbody>
</table>
</main>

View File

@@ -0,0 +1,64 @@
<script lang="ts">
export let redirect;
export let data;
export const url = "/trips/"
async function getTrips() {
let response = await fetch("http://localhost:9000/v1/trips", {
method: "GET",
headers: {
"Accept": "application/json"
},
cache: "no-store",
});
let trips = await response.json();
return trips;
}
</script>
<main>
<div class="container mx-auto mt-12">
<h2 class="text-3xl mt-12 mb-20 font-semibold text-center mb-5 mt-3">Trips</h2>
<table class="table-auto w-full">
<thead>
<tr class="font-semibold tracking-wider text-left bg-gray-100 uppercase border-b border-gray-400">
<th class="p-3">Name</th>
<th class="p-3">Date</th>
<th class="p-3">Days</th>
<th class="p-3">State</th>
<th class="p-3">Package Lists</th>
</tr>
</thead>
<tbody>
{#await getTrips()}
<p>Loading</p>
{:then trips}
{#each trips as trip}
<tr class="border" on:click={e => redirect(url + trip.id)}>
<td class="p-3">{trip.name}</td>
<td class="p-3">{trip.date}</td>
<td class="p-3">{trip.parameters.days}</td>
{#if trip.state == "active"}
<td class="p-3 bg-green-100">{trip.state}</td>
{:else if trip.state == "planned"}
<td class="p-3 bg-blue-100">{trip.state}</td>
{:else}
<td class="p-3">{trip.state}</td>
{/if}
<td class="p-3">
<ul>
{#each trip.packageLists as list}
<li><button on:click={() => redirect(`/lists/${list.id}`)}>{list.name}</button></li>
{/each}
</ul>
</td>
</tr>
{/each}
{:catch error}
<p>Error: {error}</p>
{/await}
</tbody>
</table>
</div>
</main>