RIT-Dining/RIT Dining/Components/FDMealPlannerParsers.swift
NinjaCheetah 85aa9e636d
Improvements to FD MealPlanner integration
- Detailed nutrition facts are now shown on the menu item view
- Fixed The College Grind not having a "View Menu" button (IDs were mapped incorrectly)
- Menu items are now sorted alphabetically
- "Allergens" section now hidden on the menu item view if the item contains no allergens
- Duplicate items will no longer be added to the menu item list, so no more issues with items randomly appearing and disappearing (thanks FD MealPlanner for having duplicates in the first place)
2025-11-10 01:58:23 -05:00

76 lines
4.5 KiB
Swift

//
// FDMealPlannerParsers.swift
// RIT Dining
//
// Created by Campbell on 11/3/25.
//
import Foundation
func parseFDMealPlannerMenu(menu: FDMealsParser) -> [FDMenuItem] {
var menuItems: [FDMenuItem] = []
if menu.result.isEmpty {
return menuItems
}
// We only need to operate on index 0, because the request code is designed to only get the menu for a single day so there
// will only be a single index to operate on.
if let allMenuRecipes = menu.result[0].allMenuRecipes {
for recipe in allMenuRecipes {
// Prevent duplicate items from being added, because for some reason the exact same item with the exact same information
// might be included in FD MealPlanner more than once.
if menuItems.contains(where: { $0.id == recipe.componentId }) {
continue
}
// englishAlternateName holds the proper name of the item, but it's blank for some items for some reason. If that's the
// case, then we should fall back on componentName, which is less user-friendly but works as a backup.
let realName = if recipe.englishAlternateName != "" {
recipe.englishAlternateName
} else {
recipe.componentName
}
let allergens = recipe.allergenName != "" ? recipe.allergenName.components(separatedBy: ",") : []
// Get the list of dietary markers (Vegan, Vegetarian, Pork, Beef), and drop "Vegetarian" if "Vegan" is also included since
// that's kinda redundant.
var dietaryMarkers = recipe.recipeProductDietaryName != "" ? recipe.recipeProductDietaryName.components(separatedBy: ",").map { $0.trimmingCharacters(in: .whitespaces) } : []
if dietaryMarkers.contains("Vegan") {
dietaryMarkers.remove(at: dietaryMarkers.firstIndex(of: "Vegetarian")!)
}
let calories = Int(Double(recipe.calories)!.rounded())
// Collect and organize all the nutritional entries. I ordered them based off how they were ordered in the nutritional
// facts panel on the side of the bag of goldfish that lives on my desk, so presumably they're ordered correctly.
let nutritionalEntries = [
FDNutritionalEntry(type: "Total Fat", amount: Double(recipe.fat) ?? 0.0, unit: recipe.fatUOM),
FDNutritionalEntry(type: "Saturated Fat", amount: Double(recipe.saturatedFat) ?? 0.0, unit: recipe.saturatedFatUOM),
FDNutritionalEntry(type: "Trans Fat", amount: Double(recipe.transFattyAcid) ?? 0.0, unit: recipe.transFattyAcidUOM),
FDNutritionalEntry(type: "Cholesterol", amount: Double(recipe.cholesterol) ?? 0.0, unit: recipe.cholesterolUOM),
FDNutritionalEntry(type: "Sodium", amount: Double(recipe.sodium) ?? 0.0, unit: recipe.sodiumUOM),
FDNutritionalEntry(type: "Total Carbohydrates", amount: Double(recipe.carbohydrates) ?? 0.0, unit: recipe.carbohydratesUOM),
FDNutritionalEntry(type: "Dietary Fiber", amount: Double(recipe.dietaryFiber) ?? 0.0, unit: recipe.dietaryFiberUOM),
FDNutritionalEntry(type: "Total Sugars", amount: Double(recipe.totalSugars) ?? 0.0, unit: recipe.totalSugarsUOM),
FDNutritionalEntry(type: "Protein", amount: Double(recipe.protein) ?? 0.0, unit: recipe.proteinUOM),
FDNutritionalEntry(type: "Calcium", amount: Double(recipe.calcium) ?? 0.0, unit: recipe.calciumUOM),
FDNutritionalEntry(type: "Iron", amount: Double(recipe.iron) ?? 0.0, unit: recipe.ironUOM),
FDNutritionalEntry(type: "Vitamin A", amount: Double(recipe.vitaminA) ?? 0.0, unit: recipe.vitaminAUOM),
FDNutritionalEntry(type: "Vitamin C", amount: Double(recipe.vitaminC) ?? 0.0, unit: recipe.vitaminCUOM),
]
let newItem = FDMenuItem(
id: recipe.componentId,
name: realName,
exactName: recipe.componentName,
category: recipe.category,
allergens: allergens,
calories: calories,
nutritionalEntries: nutritionalEntries,
dietaryMarkers: dietaryMarkers,
ingredients: recipe.ingredientStatement,
price: recipe.sellingPrice,
servingSize: recipe.productMeasuringSize,
servingSizeUnit: recipe.productMeasuringSizeUnit
)
menuItems.append(newItem)
}
}
return menuItems
}