Refactor #4
This commit is contained in:
parent
a6904524db
commit
8797a5489c
4 changed files with 165 additions and 139 deletions
|
|
@ -41,6 +41,7 @@ Outcome: Components get smaller and easier to read; business logic is reusable.
|
|||
- [x] Add Prettier config and .editorconfig; wire Prettier with ESLint
|
||||
- [ ] Upgrade ESLint (if/when convenient) and align with Vue 3 rules
|
||||
- [ ] Ensure Volar is used (dev environment) for Vue 3 type intelligence
|
||||
- Optional next: add lint-staged + husky for `pre-commit` formatting
|
||||
|
||||
Outcome: Stable formatting and consistent linting across contributors.
|
||||
|
||||
|
|
|
|||
|
|
@ -52,16 +52,17 @@
|
|||
<editable-ingredients-panel :ingredients="meal.extra_ingredients" @on-add="addIngredient" @on-delete="deleteIngredient" @on-update-ingredient="updateIngredient" @on-editing="onEditAdditionalIngredients" />
|
||||
</div>
|
||||
|
||||
<button @click="saveMeal">Save</button>
|
||||
<button @click="onSaveMeal">Save</button>
|
||||
<p v-if="meal.purchase_date"><em>Purchased {{ ago(meal.purchase_date) }}</em></p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import { getMeal, saveMeal } from '@/api/meals';
|
||||
import { getRecipe } from '@/api/recipes';
|
||||
import { currentUser } from '@/api/auth';
|
||||
<script setup>
|
||||
import { reactive, onBeforeMount } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { getMeal, saveMeal } from '@/composables/useMeals'
|
||||
import { getRecipe } from '@/api/recipes'
|
||||
import { currentUser } from '@/api/auth'
|
||||
import alert from '@/alert.js';
|
||||
|
||||
import { ago } from '@/dateformats.js';
|
||||
|
|
@ -79,110 +80,114 @@ function addPersonIfNotExists(list, person) {
|
|||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
props: ['id'],
|
||||
components: { RecipeSearchBox, DatePicker, RecipeCard, EditableIngredientsPanel, PersonList, CompactParsedIngredient },
|
||||
data() {
|
||||
return {
|
||||
showIngredients: {},
|
||||
meal: {
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const showIngredients = reactive({})
|
||||
const meal = reactive({
|
||||
id: -1,
|
||||
suggested_date: new Date(),
|
||||
recipes: [],
|
||||
extra_ingredients: [],
|
||||
chefs: [],
|
||||
consumers: [],
|
||||
cleanup: []
|
||||
cleanup: [],
|
||||
})
|
||||
|
||||
onBeforeMount(async () => {
|
||||
const idParam = route.params.id
|
||||
const id = typeof idParam === 'string' ? parseInt(idParam) : idParam
|
||||
if (id >= 0) {
|
||||
const loaded = await getMeal(id)
|
||||
Object.assign(meal, loaded)
|
||||
} else {
|
||||
const self = await currentUser()
|
||||
Object.assign(meal, { chefs: [self], consumers: [self], cleanup: [self] })
|
||||
}
|
||||
};
|
||||
},
|
||||
async beforeMount() {
|
||||
if (this.id >= 0) {
|
||||
this.meal = await getMeal(this.id);
|
||||
})
|
||||
|
||||
function selectDate(date) {
|
||||
meal.suggested_date = date
|
||||
}
|
||||
|
||||
function removeRecipe(mealRecipe) {
|
||||
if (confirm(`Are you sure you want to remove ${mealRecipe.servings} servings of ${mealRecipe.recipe.name} from this meal?`)) {
|
||||
meal.recipes = meal.recipes.filter((r) => r != mealRecipe)
|
||||
}
|
||||
else {
|
||||
const self = await currentUser();
|
||||
this.meal = {...this.meal, chefs: [self], consumers: [self], cleanup: [self], };
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ago,
|
||||
async selectRecipe(recipe) {
|
||||
}
|
||||
|
||||
function addIngredient() {
|
||||
meal.extra_ingredients = [{ line: '', product: null }, ...meal.extra_ingredients]
|
||||
}
|
||||
|
||||
function deleteIngredient(ingredient) {
|
||||
meal.extra_ingredients = meal.extra_ingredients.filter((i) => i != ingredient)
|
||||
}
|
||||
|
||||
function updateIngredient(ingredient, newIngredient) {
|
||||
meal.extra_ingredients = meal.extra_ingredients.map((i) => (i == ingredient ? newIngredient : i))
|
||||
}
|
||||
|
||||
function removePerson(list, person) {
|
||||
meal[list] = meal[list].filter((p) => p.id !== person.id)
|
||||
}
|
||||
|
||||
function addPerson(list, person) {
|
||||
addPersonIfNotExists(meal[list], person)
|
||||
}
|
||||
|
||||
async function selectRecipe(recipe) {
|
||||
// Refetch to get additional details
|
||||
recipe = await getRecipe(recipe.id);
|
||||
recipe = await getRecipe(recipe.id)
|
||||
|
||||
if (recipe.created_by) {
|
||||
addPersonIfNotExists(this.meal.chefs, recipe.created_by);
|
||||
addPersonIfNotExists(this.meal.consumers, recipe.created_by);
|
||||
addPersonIfNotExists(meal.chefs, recipe.created_by)
|
||||
addPersonIfNotExists(meal.consumers, recipe.created_by)
|
||||
|
||||
if (this.meal.cleanup.length === 0) {
|
||||
addPersonIfNotExists(this.meal.cleanup, recipe.created_by);
|
||||
if (meal.cleanup.length === 0) {
|
||||
addPersonIfNotExists(meal.cleanup, recipe.created_by)
|
||||
}
|
||||
}
|
||||
|
||||
this.meal.recipes.push({ recipe, recipe_id: recipe.id, meal_id: this.meal.id, servings: recipe.serves });
|
||||
},
|
||||
selectDate(date) {
|
||||
this.meal.suggested_date = date;
|
||||
},
|
||||
removeRecipe(mealRecipe) {
|
||||
if (confirm(`Are you sure you want to remove ${mealRecipe.servings} servings of ${mealRecipe.recipe.name} from this meal?`)) {
|
||||
this.meal.recipes = this.meal.recipes.filter(r => r != mealRecipe);
|
||||
}
|
||||
},
|
||||
addIngredient() {
|
||||
this.meal.extra_ingredients = [{ line: '', product: null }, ...this.meal.extra_ingredients];
|
||||
},
|
||||
deleteIngredient(ingredient) {
|
||||
this.meal.extra_ingredients = this.meal.extra_ingredients.filter(i => i != ingredient);
|
||||
},
|
||||
updateIngredient(ingredient, newIngredient) {
|
||||
this.meal.extra_ingredients = this.meal.extra_ingredients.map(i => i == ingredient ? newIngredient : i);
|
||||
},
|
||||
removePerson(list, person) {
|
||||
this.meal[list] = this.meal[list].filter(p => p.id !== person.id);
|
||||
},
|
||||
addPerson(list, person) {
|
||||
addPersonIfNotExists(this.meal[list], person);
|
||||
},
|
||||
async saveMeal() {
|
||||
const meal = await saveMeal(this.meal);
|
||||
if (meal?.id >= 0) {
|
||||
this.meal = meal;
|
||||
meal.recipes.push({ recipe, recipe_id: recipe.id, meal_id: meal.id, servings: recipe.serves })
|
||||
}
|
||||
|
||||
this.$router.push(`/meals/${meal.id}`);
|
||||
alert.show({ heading: 'Meal saved', message: 'Meal saved successfully', type: 'success' });
|
||||
return;
|
||||
async function onEditAdditionalIngredients(editing) {
|
||||
if (editing && meal.extra_ingredients.length === 0) {
|
||||
addIngredient()
|
||||
} else {
|
||||
meal.extra_ingredients = meal.extra_ingredients.filter((i) => i.line)
|
||||
}
|
||||
}
|
||||
|
||||
alert.show({ heading: 'Error saving meal', message: 'An error occurred while saving the meal', type: 'error' });
|
||||
},
|
||||
onEditAdditionalIngredients(editing) {
|
||||
if (editing && this.meal.extra_ingredients.length === 0) {
|
||||
this.addIngredient();
|
||||
}
|
||||
else {
|
||||
this.meal.extra_ingredients = this.meal.extra_ingredients.filter(i => i.line);
|
||||
}
|
||||
},
|
||||
showIngredient(mealRecipe, value) {
|
||||
const index = this.meal.recipes.indexOf(mealRecipe);
|
||||
const key = `${mealRecipe.recipe.id}-${index}`;
|
||||
function showIngredient(mealRecipe, value) {
|
||||
const index = meal.recipes.indexOf(mealRecipe)
|
||||
const key = `${mealRecipe.recipe.id}-${index}`
|
||||
if (value === undefined) {
|
||||
return this.showIngredients[key];
|
||||
return showIngredients[key]
|
||||
}
|
||||
return (showIngredients[key] = value)
|
||||
}
|
||||
|
||||
return this.showIngredients[key] = value;
|
||||
},
|
||||
scaleIngredients(mealRecipe) {
|
||||
return mealRecipe.recipe.ingredients.map(i => {
|
||||
function scaleIngredients(mealRecipe) {
|
||||
return mealRecipe.recipe.ingredients.map((i) => {
|
||||
return {
|
||||
...i,
|
||||
quantity: i.quantity * mealRecipe.servings / mealRecipe.recipe.serves
|
||||
};
|
||||
});
|
||||
},
|
||||
quantity: (i.quantity * mealRecipe.servings) / mealRecipe.recipe.serves,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function onSaveMeal() {
|
||||
const saved = await saveMeal(meal)
|
||||
if (saved?.id >= 0) {
|
||||
Object.assign(meal, saved)
|
||||
router.push(`/meals/${saved.id}`)
|
||||
alert.show({ heading: 'Meal saved', message: 'Meal saved successfully', type: 'success' })
|
||||
return
|
||||
}
|
||||
|
||||
alert.show({ heading: 'Error saving meal', message: 'An error occurred while saving the meal', type: 'error' })
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -78,41 +78,36 @@ ul.actions {
|
|||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { ref, onBeforeMount } from 'vue'
|
||||
import ActionItem from '@/components/ActionItem.vue'
|
||||
import MealCard from '@/components/meals/MealCard.vue'
|
||||
import { getUpcomingMeals, markMealConsumed, deleteMeal } from '@/api/meals'
|
||||
import { getUpcomingMeals, markMealConsumed, deleteMeal } from '@/composables/useMeals'
|
||||
|
||||
export default {
|
||||
name: 'MealPlanPage',
|
||||
components: { MealCard, ActionItem },
|
||||
data() {
|
||||
const from = new Date();
|
||||
from.setTime(0);
|
||||
|
||||
const to = new Date();
|
||||
to.setDate(to.getDate() + 7);
|
||||
const from = new Date()
|
||||
from.setTime(0)
|
||||
|
||||
return {
|
||||
from, to,
|
||||
meals: [],
|
||||
selectedMeal: null
|
||||
}
|
||||
},
|
||||
async beforeMount() {
|
||||
const meals = await getUpcomingMeals(this.from, this.to)
|
||||
this.meals = meals
|
||||
},
|
||||
methods: {
|
||||
async deleteSelectedMeal() {
|
||||
await deleteMeal(this.selectedMeal.id)
|
||||
this.meals = this.meals.filter(m => m.id !== this.selectedMeal.id)
|
||||
this.selectedMeal = null
|
||||
},
|
||||
async markConsumed() {
|
||||
await markMealConsumed(this.selectedMeal.id)
|
||||
this.meals = this.meals.filter(m => m.id !== this.selectedMeal.id)
|
||||
}
|
||||
}
|
||||
const to = new Date()
|
||||
to.setDate(to.getDate() + 7)
|
||||
|
||||
const meals = ref([])
|
||||
const selectedMeal = ref(null)
|
||||
|
||||
onBeforeMount(async () => {
|
||||
meals.value = await getUpcomingMeals(from, to)
|
||||
})
|
||||
|
||||
async function deleteSelectedMeal() {
|
||||
if (!selectedMeal.value) return
|
||||
await deleteMeal(selectedMeal.value.id)
|
||||
meals.value = meals.value.filter((m) => m.id !== selectedMeal.value.id)
|
||||
selectedMeal.value = null
|
||||
}
|
||||
|
||||
async function markConsumed() {
|
||||
if (!selectedMeal.value) return
|
||||
await markMealConsumed(selectedMeal.value.id)
|
||||
meals.value = meals.value.filter((m) => m.id !== selectedMeal.value.id)
|
||||
}
|
||||
</script>
|
||||
25
src/composables/useMeals.js
Normal file
25
src/composables/useMeals.js
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import * as api from '@/api/meals'
|
||||
|
||||
export async function getUpcomingMeals(from, to) {
|
||||
return api.getUpcomingMeals(from, to)
|
||||
}
|
||||
|
||||
export async function getMeal(id) {
|
||||
return api.getMeal(id)
|
||||
}
|
||||
|
||||
export async function saveMeal(meal) {
|
||||
return api.saveMeal(meal)
|
||||
}
|
||||
|
||||
export async function markMealConsumed(mealId) {
|
||||
return api.markMealConsumed(mealId)
|
||||
}
|
||||
|
||||
export async function deleteMeal(mealId) {
|
||||
return api.deleteMeal(mealId)
|
||||
}
|
||||
|
||||
export function useMeals() {
|
||||
return { getUpcomingMeals, getMeal, saveMeal, markMealConsumed, deleteMeal }
|
||||
}
|
||||
Loading…
Reference in a new issue