- Migration 035: add sensory_tags column to recipes (default '{}')
- scripts/tag_sensory_profiles.py: batch tagger using ingredient names,
direction keywords, and ingredient_profiles texture data
- app/services/recipe/sensory.py: SensoryExclude frozen dataclass,
build_sensory_exclude(), passes_sensory_filter() with graceful degradation
(untagged recipes always pass; malformed JSON always passes)
- store.browse_recipes and _browse_by_match: accept SensoryExclude, apply
filter in recipe-building loop (default path) and scoring loop (match sort)
- recipe_engine.suggest: load sensory_preferences from settings, apply
passes_sensory_filter() after exclude_set check in the rows loop
- settings endpoint: add sensory_preferences to _ALLOWED_KEYS
- Frontend: SensoryPreferences types in api.ts; sensoryPreferences state and
saveSensory() action in settings store; Sensory section in SettingsView with
texture avoid pills, smell/noise tolerance scale pills with ok/limit/neutral
color coding
- 66 new tests (29 classification + 13 sensory service + 2 settings); 281 total
106 lines
3.1 KiB
TypeScript
106 lines
3.1 KiB
TypeScript
/**
|
|
* Settings Store
|
|
*
|
|
* Manages user settings (cooking equipment, preferences) using Pinia.
|
|
*/
|
|
|
|
import { defineStore } from 'pinia'
|
|
import { ref } from 'vue'
|
|
import { settingsAPI } from '../services/api'
|
|
import type { UnitSystem } from '../utils/units'
|
|
import type { SensoryPreferences } from '../services/api'
|
|
import { DEFAULT_SENSORY_PREFERENCES } from '../services/api'
|
|
|
|
export const useSettingsStore = defineStore('settings', () => {
|
|
// State
|
|
const cookingEquipment = ref<string[]>([])
|
|
const unitSystem = ref<UnitSystem>('metric')
|
|
const shoppingLocale = ref<string>('us')
|
|
const sensoryPreferences = ref<SensoryPreferences>({ ...DEFAULT_SENSORY_PREFERENCES })
|
|
const loading = ref(false)
|
|
const saved = ref(false)
|
|
|
|
// Actions
|
|
async function load() {
|
|
loading.value = true
|
|
try {
|
|
const [rawEquipment, rawUnits, rawLocale, rawSensory] = await Promise.allSettled([
|
|
settingsAPI.getSetting('cooking_equipment'),
|
|
settingsAPI.getSetting('unit_system'),
|
|
settingsAPI.getSetting('shopping_locale'),
|
|
settingsAPI.getSetting('sensory_preferences'),
|
|
])
|
|
if (rawEquipment.status === 'fulfilled' && rawEquipment.value) {
|
|
cookingEquipment.value = JSON.parse(rawEquipment.value)
|
|
}
|
|
if (rawUnits.status === 'fulfilled' && rawUnits.value) {
|
|
unitSystem.value = rawUnits.value as UnitSystem
|
|
}
|
|
if (rawLocale.status === 'fulfilled' && rawLocale.value) {
|
|
shoppingLocale.value = rawLocale.value
|
|
}
|
|
if (rawSensory.status === 'fulfilled' && rawSensory.value) {
|
|
try {
|
|
sensoryPreferences.value = JSON.parse(rawSensory.value)
|
|
} catch {
|
|
sensoryPreferences.value = { ...DEFAULT_SENSORY_PREFERENCES }
|
|
}
|
|
}
|
|
} catch (err: unknown) {
|
|
console.error('Failed to load settings:', err)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function save() {
|
|
loading.value = true
|
|
try {
|
|
await Promise.all([
|
|
settingsAPI.setSetting('cooking_equipment', JSON.stringify(cookingEquipment.value)),
|
|
settingsAPI.setSetting('unit_system', unitSystem.value),
|
|
settingsAPI.setSetting('shopping_locale', shoppingLocale.value),
|
|
settingsAPI.setSetting('sensory_preferences', JSON.stringify(sensoryPreferences.value)),
|
|
])
|
|
saved.value = true
|
|
setTimeout(() => {
|
|
saved.value = false
|
|
}, 2000)
|
|
} catch (err: unknown) {
|
|
console.error('Failed to save settings:', err)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
async function saveSensory() {
|
|
loading.value = true
|
|
try {
|
|
await settingsAPI.setSetting(
|
|
'sensory_preferences',
|
|
JSON.stringify(sensoryPreferences.value),
|
|
)
|
|
saved.value = true
|
|
setTimeout(() => { saved.value = false }, 2000)
|
|
} catch (err: unknown) {
|
|
console.error('Failed to save sensory preferences:', err)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
return {
|
|
// State
|
|
cookingEquipment,
|
|
unitSystem,
|
|
shoppingLocale,
|
|
sensoryPreferences,
|
|
loading,
|
|
saved,
|
|
|
|
// Actions
|
|
load,
|
|
save,
|
|
saveSensory,
|
|
}
|
|
})
|