Skip to main content

max / makenotwork

6.4 KB · 182 lines History Blame Raw
1 //! Step rendering dispatcher for the item wizard.
2
3 use axum::response::{IntoResponse, Response};
4 use tower_sessions::Session;
5
6 use crate::{
7 db::{self, ItemType, ProjectFeature},
8 error::{AppError, Result},
9 helpers::get_csrf_token,
10 templates::*,
11 AppState,
12 };
13
14 use super::{build_step_nav, format_price_display, ITEM_LABELS, ITEM_STEPS};
15
16 pub(super) async fn render_step(
17 state: &AppState,
18 session: &Session,
19 _user: &crate::auth::SessionUser,
20 project: &db::DbProject,
21 item: &db::DbItem,
22 step: &str,
23 ) -> Result<Response> {
24 let nav = build_step_nav(ITEM_STEPS, ITEM_LABELS, step);
25 let project_slug = project.slug.to_string();
26 let item_id = item.id.to_string();
27 let csrf_token = get_csrf_token(session).await;
28
29 match step {
30 "type" => {
31 let type_cards = ProjectFeature::wizard_type_cards(&project.features);
32 // If only 1 behavior group, skip forward to basics
33 if type_cards.len() <= 1 {
34 let nav = build_step_nav(ITEM_STEPS, ITEM_LABELS, "basics");
35 return Ok(WizardItemBasicsTemplate {
36 nav,
37 project_slug,
38 item_id,
39 title: item.title.clone(),
40 description: item.description.clone().unwrap_or_default(),
41 cover_image_url: item.cover_image_url.clone(),
42 }
43 .into_response());
44 }
45 Ok(WizardItemTypeTemplate {
46 nav,
47 project_slug,
48 item_id,
49 item_type_cards: type_cards,
50 selected_type: item.item_type.to_string(),
51 }
52 .into_response())
53 }
54
55 "basics" => Ok(WizardItemBasicsTemplate {
56 nav,
57 project_slug,
58 item_id,
59 title: item.title.clone(),
60 description: item.description.clone().unwrap_or_default(),
61 cover_image_url: item.cover_image_url.clone(),
62 }
63 .into_response()),
64
65 "content" => {
66 let content_template = item.item_type.to_string();
67
68 // Load bundle data if this is a bundle item
69 let (bundleable_items, selected_bundle_ids, unlisted_ids) =
70 if item.item_type == ItemType::Bundle {
71 let bundleable =
72 db::bundles::get_bundleable_items(&state.db, project.id, Some(item.id))
73 .await?;
74 let current = db::bundles::get_bundle_items(&state.db, item.id).await?;
75 let selected: Vec<String> =
76 current.iter().map(|i| i.id.to_string()).collect();
77 let unlisted: Vec<String> = current
78 .iter()
79 .chain(bundleable.iter())
80 .filter(|i| !i.listed)
81 .map(|i| i.id.to_string())
82 .collect();
83 let bi: Vec<BundleableItem> = bundleable
84 .iter()
85 .map(|i| BundleableItem {
86 id: i.id.to_string(),
87 title: i.title.clone(),
88 item_type: i.item_type.label().to_string(),
89 })
90 .collect();
91 (bi, selected, unlisted)
92 } else {
93 (vec![], vec![], vec![])
94 };
95
96 Ok(WizardItemContentTemplate {
97 nav,
98 project_slug,
99 project_id: project.id.to_string(),
100 item_id,
101 item_type: content_template,
102 body: item.body.clone().unwrap_or_default(),
103 bundleable_items,
104 selected_bundle_ids,
105 unlisted_ids,
106 }
107 .into_response())
108 }
109
110 "sections" => {
111 let db_sections = db::item_sections::list_by_item(&state.db, item.id).await?;
112 let sections: Vec<crate::types::ItemSection> =
113 db_sections.iter().map(crate::types::ItemSection::from).collect();
114 Ok(WizardItemSectionsTemplate {
115 nav,
116 project_slug,
117 item_id,
118 sections,
119 }
120 .into_response())
121 }
122
123 "pricing" => {
124 let pricing_model = if item.pwyw_enabled {
125 "pwyw"
126 } else if item.price_cents > 0 {
127 "fixed"
128 } else {
129 "free"
130 };
131
132 Ok(WizardItemPricingTemplate {
133 nav,
134 project_slug,
135 item_id,
136 pricing_model: pricing_model.to_string(),
137 price_dollars: format!(
138 "{}.{:02}",
139 item.price_cents / 100,
140 item.price_cents % 100
141 ),
142 pwyw_suggested_dollars: format!(
143 "{}.{:02}",
144 item.price_cents / 100,
145 item.price_cents % 100
146 ),
147 pwyw_min_dollars: {
148 let min = item.pwyw_min_cents.unwrap_or(0);
149 format!("{}.{:02}", min / 100, min % 100)
150 },
151 }
152 .into_response())
153 }
154
155 "preview" => {
156 let tags = db::tags::get_tags_for_item(&state.db, item.id).await?;
157 let tag_names: Vec<String> = tags.iter().map(|t| t.tag_name.clone()).collect();
158
159 Ok(WizardItemPreviewTemplate {
160 csrf_token,
161 nav,
162 project_slug,
163 item_id,
164 title: item.title.clone(),
165 item_type: item.item_type.to_string(),
166 description: item.description.clone().unwrap_or_default(),
167 price_display: format_price_display(item.price_cents, item.pwyw_enabled, item.pwyw_min_cents),
168 tag_names,
169 has_content: item.body.is_some()
170 || item.audio_s3_key.is_some()
171 || item.video_s3_key.is_some()
172 || (item.item_type == ItemType::Bundle
173 && db::bundles::get_bundle_item_count(&state.db, item.id).await? > 0),
174 is_public: item.is_public,
175 }
176 .into_response())
177 }
178
179 _ => Err(AppError::NotFound),
180 }
181 }
182