Skip to content

Commit

Permalink
chore: factor meal_card into separate module
Browse files Browse the repository at this point in the history
  • Loading branch information
jdevries3133 committed Jun 30, 2024
1 parent 1701102 commit 3fe485a
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 239 deletions.
7 changes: 7 additions & 0 deletions src/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,3 +631,10 @@ impl Component for Span {
format!("<span>{}</span>", clean(&self.content))
}
}

pub struct Void;
impl Component for Void {
fn render(&self) -> String {
"".into()
}
}
108 changes: 3 additions & 105 deletions src/count_chat/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
//! are colocated here).
use super::{
meal_card::{MealCard, RenderingBehavior},
openai::OpenAI,
prev_meal_list::{MealCard, MealSet, PreviousMeals, RenderingBehavior},
prev_meal_list::{MealSet, PrevDayFormActions, PreviousMeals},
Meal, MealInfo,
};
use crate::{
auth::is_anon, client_events, components::AnonWarning, config,
Expand All @@ -12,41 +14,6 @@ use crate::{
use axum::extract::Query;
use futures::join;

#[derive(Debug)]
pub struct Meal {
pub id: i32,
pub info: MealInfo,
}

#[derive(Debug, Deserialize)]
pub struct MealInfo {
pub calories: i32,
pub protein_grams: i32,
pub carbohydrates_grams: i32,
pub fat_grams: i32,
pub meal_name: String,
pub created_at: DateTime<Utc>,
}

struct Void;
impl Component for Void {
fn render(&self) -> String {
"".into()
}
}
impl Component for Meal {
fn render(&self) -> String {
MealCard {
meal_id: Some(self.id),
info: &self.info,
actions: Some(&Void {}),
rendering_behavior: RenderingBehavior::RenderAsToday,
show_ai_warning: false,
}
.render()
}
}

pub struct Chat<'a> {
pub meals: &'a Vec<Meal>,
pub prompt: Option<&'a str>,
Expand Down Expand Up @@ -505,75 +472,6 @@ pub async fn list_meals(
.render())
}

struct PrevDayFormActions<'a> {
info: &'a MealInfo,
}
impl Component for PrevDayFormActions<'_> {
fn render(&self) -> String {
let save_meal = Route::SaveMeal;
let created_at = self.info.created_at.format("%d/%m/%Y");
let script = include_str!("./custom_date_widget_helper.js");
let meal_name = encode_quotes(&clean(&self.info.meal_name));
let calories = self.info.calories;
let protein = self.info.protein_grams;
let carbs = self.info.carbohydrates_grams;
let fat = self.info.fat_grams;
format!(
r##"
<form
hx-post="{save_meal}"
hx-target="closest div[data-name='meal-card']"
class="flex flex-col">
<label for="created_date">
Date
</label>
<input
required
value="{created_at}"
type="date"
name="created_date"
id="created_date"
/>
<!-- This field gets populated by JS when the buttons below are
clicked -->
<input type="hidden" name="created_at" id="created_at" />
<input type="hidden" value="{meal_name}" name="meal_name" />
<input type="hidden" value="{calories}" name="calories" />
<input type="hidden" value="{protein}" name="protein_grams" />
<input type="hidden" value="{carbs}" name="carbohydrates_grams" />
<input type="hidden" value="{fat}" name="fat_grams" />
<p class="text-sm">Approximately what time of day was this meal?</p>
<button
class="block p-2 m-2 bg-blue-100 hover:bg-blue-200 rounded shadow hover:shadow-none"
id="breakfast"
>
Breakfast
</button>
<button
class="block p-2 m-2 bg-blue-100 hover:bg-blue-200 rounded shadow hover:shadow-none"
id="lunch"
>
Lunch
</button>
<button
class="block p-2 m-2 bg-blue-100 hover:bg-blue-200 rounded shadow hover:shadow-none"
id="dinner"
>
Dinner
</button>
<button
class="block p-2 m-2 bg-blue-100 hover:bg-blue-200 rounded shadow hover:shadow-none"
id="evening"
>
Evening
</button>
<script>(() => {{{script}}})();</script>
</form>
"##
)
}
}

pub async fn prev_day_meal_form(
State(AppState { db }): State<AppState>,
headers: HeaderMap,
Expand Down
2 changes: 1 addition & 1 deletion src/count_chat/llm_parse_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! next time an a resonably well-structured declarative way. Inspired by
//! https://www.youtube.com/watch?v=yj-wSRJwrrc.
use super::counter::MealInfo;
use super::MealInfo;
use crate::chrono_utils::utc_now;
use regex::{Captures, Regex};

Expand Down
159 changes: 159 additions & 0 deletions src/count_chat/meal_card.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use crate::{chrono_utils::is_before_today, components::Void, prelude::*};

#[derive(Debug)]
pub struct Meal {
pub id: i32,
pub info: MealInfo,
}

#[derive(Debug, Deserialize)]
pub struct MealInfo {
pub calories: i32,
pub protein_grams: i32,
pub carbohydrates_grams: i32,
pub fat_grams: i32,
pub meal_name: String,
pub created_at: DateTime<Utc>,
}

impl Component for Meal {
fn render(&self) -> String {
MealCard {
meal_id: Some(self.id),
info: &self.info,
actions: Some(&Void {}),
rendering_behavior: RenderingBehavior::RenderAsToday,
show_ai_warning: false,
}
.render()
}
}

pub enum RenderingBehavior {
UseTimezone(Tz),
RenderAsToday,
}

pub struct MealCard<'a> {
pub info: &'a MealInfo,
pub meal_id: Option<i32>,
pub actions: Option<&'a dyn Component>,
pub rendering_behavior: RenderingBehavior,
pub show_ai_warning: bool,
}
impl Component for MealCard<'_> {
fn render(&self) -> String {
let is_meal_before_today = match self.rendering_behavior {
RenderingBehavior::UseTimezone(tz) => {
is_before_today(&self.info.created_at, tz)
}
RenderingBehavior::RenderAsToday => false,
};
let meal_name = clean(&self.info.meal_name);
let calories = self.info.calories;
let protein = self.info.protein_grams;
let carbs = self.info.carbohydrates_grams;
let fat = self.info.fat_grams;
let actions = match &self.actions {
Some(action) => action.render(),
None => match self.meal_id {
Some(id) => {
let delete_href = Route::DeleteMeal(Some(id));
let add_to_today_href = Route::AddMealToToday(Some(id));
let add_to_today_button = if is_meal_before_today {
format!(
r#"
<button
hx-post="{add_to_today_href}"
hx-target="closest div[data-name='meal-card']"
class="
align-self-right
bg-emerald-100
hover:bg-emerald-200
rounded
p-1
dark:text-black
">
Add to Today
</button>
"#
)
} else {
format!(
r#"
<button
hx-post="{add_to_today_href}"
hx-target="closest div[data-name='meal-card']"
class="
align-self-right
bg-emerald-100
hover:bg-emerald-200
rounded
p-1
dark:text-black
">
Duplicate
</button>
"#
)
};
format!(
r#"
{add_to_today_button}
<button
hx-delete="{delete_href}"
hx-target="closest div[data-name='meal-card']"
class="align-self-right bg-red-100 hover:bg-red-200
rounded p-1 dark:text-black"
>
Delete
</button>"#
)
}
None => "".into(),
},
};
let background_style = if is_meal_before_today {
"border-4 border-black dark:border-slate-200 md:dark:border-black"
} else {
r#"bg-gradient-to-br from-blue-100 via-sky-100 to-indigo-200
dark:bg-gradient-to-br dark:from-blue-300 dark:via-cyan-300 =
dark:to-indigo-300 dark:text-black"#
};
let warning = if self.show_ai_warning {
r#"
<p
class="text-xs bg-yellow-100 dark:bg-yellow-800
dark:text-slate-200 p-2 rounded-xl my-2"
>
<span class="font-semibold">Warning:</span>
this is an AI estimate. Use discretion and re-prompt if it
doesn't look quite right!
</p>
"#
} else {
""
};
format!(
r##"
<div
class="rounded p-2 shadow sm:w-[20rem]
{background_style}
"
data-name="meal-card"
hx-swap="outerHTML"
>
<h1 class="text-2xl bold serif">{meal_name}</h1>
<p class="text-lg"><b>Calories:</b> {calories} kcal</p>
<p class="text-sm"><b>Protein:</b> {protein} grams</p>
<p class="text-sm"><b>Carbs:</b> {carbs} grams</p>
<p class="text-sm"><b>Fat:</b> {fat} grams</p>
{warning}
<div class="flex justify-end gap-2">
{actions}
</div>
</div>
"##
)
}
}
10 changes: 7 additions & 3 deletions src/count_chat/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
mod counter;
mod llm_parse_response;
mod meal_card;
mod openai;
mod prev_meal_list;

pub use self::counter::{
chat_form, handle_chat, handle_save_meal, list_meals, list_meals_op,
prev_day_meal_form, Chat as ChatContainer, Meal, MealInfo,
pub use self::{
counter::{
chat_form, handle_chat, handle_save_meal, list_meals, list_meals_op,
prev_day_meal_form, Chat as ChatContainer,
},
meal_card::{Meal, MealInfo},
};
Loading

0 comments on commit 3fe485a

Please sign in to comment.