Calendar is now displayed on home page and recipes can be scheduled without being logged

This commit is contained in:
Greg Burri 2025-02-08 22:31:38 +01:00
parent ccb1248da3
commit 37721ac3ea
22 changed files with 538 additions and 166 deletions

View file

@ -0,0 +1,150 @@
use chrono::{Datelike, Days, Months, NaiveDate};
use common::ron_api;
use gloo::storage::{LocalStorage, Storage};
use ron::ser::{to_string_pretty, PrettyConfig};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use crate::{calendar, request};
#[derive(Error, Debug)]
pub enum Error {
#[error("Request error: {0}")]
Request(#[from] request::Error),
}
type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Copy)]
pub struct RecipeScheduler {
is_local: bool,
}
pub enum ScheduleRecipeResult {
Ok,
RecipeAlreadyScheduledAtThisDate,
}
impl From<ron_api::ScheduleRecipeResult> for ScheduleRecipeResult {
fn from(api_res: ron_api::ScheduleRecipeResult) -> Self {
match api_res {
ron_api::ScheduleRecipeResult::Ok => Self::Ok,
ron_api::ScheduleRecipeResult::RecipeAlreadyScheduledAtThisDate => {
Self::RecipeAlreadyScheduledAtThisDate
}
}
}
}
#[derive(Serialize, Deserialize, Clone, Debug)]
struct ScheduledRecipesStore {
recipe_id: i64,
date: NaiveDate,
}
fn build_key(year: i32, month: u32) -> String {
format!("scheduled_recipes-{}-{}", year, month)
}
fn load_scheduled_recipes(year: i32, month: u32) -> Vec<ScheduledRecipesStore> {
LocalStorage::get::<Vec<ScheduledRecipesStore>>(build_key(year, month)).unwrap_or_default()
}
fn save_scheduled_recipes(scheduled_recipes: Vec<ScheduledRecipesStore>, year: i32, month: u32) {
LocalStorage::set(build_key(year, month), scheduled_recipes).unwrap();
}
impl RecipeScheduler {
pub fn new(is_local: bool) -> Self {
Self { is_local }
}
pub async fn get_scheduled_recipes(
&self,
start_date: NaiveDate,
end_date: NaiveDate,
) -> Result<Vec<(NaiveDate, String, i64)>> {
if self.is_local {
let mut recipe_ids_and_dates = vec![];
let mut current_date = start_date;
while current_date <= end_date {
current_date = current_date + Months::new(1);
for recipe in load_scheduled_recipes(current_date.year(), current_date.month0()) {
if recipe.date >= start_date && recipe.date <= end_date {
recipe_ids_and_dates.push(recipe);
}
}
}
if recipe_ids_and_dates.is_empty() {
return Ok(vec![]);
}
let titles: ron_api::Strings = request::get(
"recipe/get_titles",
ron_api::Ids {
ids: recipe_ids_and_dates
.iter()
.map(|r| r.recipe_id)
.collect::<Vec<_>>(),
},
)
.await?;
Ok(recipe_ids_and_dates
.iter()
.zip(titles.strs.into_iter())
.map(|(id_and_date, title)| (id_and_date.date, title, id_and_date.recipe_id))
.collect::<Vec<_>>())
} else {
let scheduled_recipes: ron_api::ScheduledRecipes = request::get(
"calendar/get_scheduled_recipes",
ron_api::DateRange {
start_date,
end_date,
},
)
.await?;
Ok(scheduled_recipes.recipes)
}
}
pub async fn shedule_recipe(
&self,
recipe_id: i64,
date: NaiveDate,
servings: u32,
) -> Result<ScheduleRecipeResult> {
if self.is_local {
// storage.get(format("scheduled_recipes-{}-{}", )
// storage.set("asd", "hello").unwrap();
let mut recipe_ids_and_dates = load_scheduled_recipes(date.year(), date.month0());
for recipe in recipe_ids_and_dates.iter() {
if recipe.recipe_id == recipe_id && recipe.date == date {
return Ok(ScheduleRecipeResult::RecipeAlreadyScheduledAtThisDate);
}
}
recipe_ids_and_dates.push(ScheduledRecipesStore { recipe_id, date });
save_scheduled_recipes(recipe_ids_and_dates, date.year(), date.month0());
Ok(ScheduleRecipeResult::Ok)
} else {
request::post::<ron_api::ScheduleRecipeResult, _>(
"calendar/schedule_recipe",
ron_api::ScheduleRecipe {
recipe_id,
date,
servings,
},
)
.await
.map_err(Error::from)
.map(From::<ron_api::ScheduleRecipeResult>::from)
}
}
// pub async fn remove_scheduled_recipe(
// &self,
// recipe_id: i64
// )
}