mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-08-03 20:45:23 +02:00
fix: Better UX and Error Handling For Adding Timeline Events (#5798)
This commit is contained in:
parent
0df9d4b958
commit
fb4aa2b713
3 changed files with 69 additions and 24 deletions
|
@ -3,6 +3,7 @@
|
||||||
<div>
|
<div>
|
||||||
<BaseDialog
|
<BaseDialog
|
||||||
v-model="madeThisDialog"
|
v-model="madeThisDialog"
|
||||||
|
:loading="madeThisFormLoading"
|
||||||
:icon="$globals.icons.chefHat"
|
:icon="$globals.icons.chefHat"
|
||||||
:title="$t('recipe.made-this')"
|
:title="$t('recipe.made-this')"
|
||||||
:submit-text="$t('recipe.add-to-timeline')"
|
:submit-text="$t('recipe.add-to-timeline')"
|
||||||
|
@ -119,8 +120,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { whenever } from "@vueuse/core";
|
import { whenever } from "@vueuse/core";
|
||||||
import { useUserApi } from "~/composables/api";
|
import { useUserApi } from "~/composables/api";
|
||||||
|
import { alert } from "~/composables/use-toast";
|
||||||
import { useHouseholdSelf } from "~/composables/use-households";
|
import { useHouseholdSelf } from "~/composables/use-households";
|
||||||
import type { Recipe, RecipeTimelineEventIn } from "~/lib/api/types/recipe";
|
import type { Recipe, RecipeTimelineEventIn, RecipeTimelineEventOut } from "~/lib/api/types/recipe";
|
||||||
import type { VForm } from "~/types/auto-forms";
|
import type { VForm } from "~/types/auto-forms";
|
||||||
|
|
||||||
export default defineNuxtComponent({
|
export default defineNuxtComponent({
|
||||||
|
@ -196,12 +198,25 @@ export default defineNuxtComponent({
|
||||||
newTimelineEventImagePreviewUrl.value = URL.createObjectURL(fileObject);
|
newTimelineEventImagePreviewUrl.value = URL.createObjectURL(fileObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = reactive({ datePickerMenu: false });
|
const state = reactive({ datePickerMenu: false, madeThisFormLoading: false });
|
||||||
|
|
||||||
|
function resetMadeThisForm() {
|
||||||
|
state.madeThisFormLoading = false;
|
||||||
|
|
||||||
|
newTimelineEvent.value.eventMessage = "";
|
||||||
|
newTimelineEvent.value.timestamp = undefined;
|
||||||
|
clearImage();
|
||||||
|
madeThisDialog.value = false;
|
||||||
|
domMadeThisForm.value?.reset();
|
||||||
|
}
|
||||||
|
|
||||||
async function createTimelineEvent() {
|
async function createTimelineEvent() {
|
||||||
if (!(newTimelineEventTimestampString.value && props.recipe?.id && props.recipe?.slug)) {
|
if (!(newTimelineEventTimestampString.value && props.recipe?.id && props.recipe?.slug)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.madeThisFormLoading = true;
|
||||||
|
|
||||||
newTimelineEvent.value.recipeId = props.recipe.id;
|
newTimelineEvent.value.recipeId = props.recipe.id;
|
||||||
// Note: $auth.user is now a ref
|
// Note: $auth.user is now a ref
|
||||||
newTimelineEvent.value.subject = i18n.t("recipe.user-made-this", { user: $auth.user.value?.fullName });
|
newTimelineEvent.value.subject = i18n.t("recipe.user-made-this", { user: $auth.user.value?.fullName });
|
||||||
|
@ -210,34 +225,60 @@ export default defineNuxtComponent({
|
||||||
// we choose the end of day so it always comes after "new recipe" events
|
// we choose the end of day so it always comes after "new recipe" events
|
||||||
newTimelineEvent.value.timestamp = new Date(newTimelineEventTimestampString.value + "T23:59:59").toISOString();
|
newTimelineEvent.value.timestamp = new Date(newTimelineEventTimestampString.value + "T23:59:59").toISOString();
|
||||||
|
|
||||||
const eventResponse = await userApi.recipes.createTimelineEvent(newTimelineEvent.value);
|
let newEvent: RecipeTimelineEventOut | null = null;
|
||||||
const newEvent = eventResponse.data;
|
try {
|
||||||
|
const eventResponse = await userApi.recipes.createTimelineEvent(newTimelineEvent.value);
|
||||||
|
newEvent = eventResponse.data;
|
||||||
|
if (!newEvent) {
|
||||||
|
throw new Error("No event created");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error("Failed to create timeline event:", error);
|
||||||
|
alert.error(i18n.t("recipe.failed-to-add-to-timeline"));
|
||||||
|
resetMadeThisForm();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// we also update the recipe's last made value
|
// we also update the recipe's last made value
|
||||||
if (!lastMade.value || newTimelineEvent.value.timestamp > lastMade.value) {
|
if (!lastMade.value || newTimelineEvent.value.timestamp > lastMade.value) {
|
||||||
lastMade.value = newTimelineEvent.value.timestamp;
|
try {
|
||||||
await userApi.recipes.updateLastMade(props.recipe.slug, newTimelineEvent.value.timestamp);
|
lastMade.value = newTimelineEvent.value.timestamp;
|
||||||
}
|
await userApi.recipes.updateLastMade(props.recipe.slug, newTimelineEvent.value.timestamp);
|
||||||
|
}
|
||||||
// update the image, if provided
|
catch (error) {
|
||||||
if (newTimelineEventImage.value && newEvent) {
|
console.error("Failed to update last made date:", error);
|
||||||
const imageResponse = await userApi.recipes.updateTimelineEventImage(
|
alert.error(i18n.t("recipe.failed-to-update-recipe"));
|
||||||
newEvent.id,
|
|
||||||
newTimelineEventImage.value,
|
|
||||||
newTimelineEventImageName.value,
|
|
||||||
);
|
|
||||||
if (imageResponse.data) {
|
|
||||||
newEvent.image = imageResponse.data.image;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset form
|
// update the image, if provided
|
||||||
newTimelineEvent.value.eventMessage = "";
|
let imageError = false;
|
||||||
newTimelineEvent.value.timestamp = undefined;
|
if (newTimelineEventImage.value) {
|
||||||
clearImage();
|
try {
|
||||||
madeThisDialog.value = false;
|
const imageResponse = await userApi.recipes.updateTimelineEventImage(
|
||||||
domMadeThisForm.value?.reset();
|
newEvent.id,
|
||||||
|
newTimelineEventImage.value,
|
||||||
|
newTimelineEventImageName.value,
|
||||||
|
);
|
||||||
|
if (imageResponse.data) {
|
||||||
|
newEvent.image = imageResponse.data.image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
imageError = true;
|
||||||
|
console.error("Failed to upload image for timeline event:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (imageError) {
|
||||||
|
alert.error(i18n.t("recipe.added-to-timeline-but-failed-to-add-image"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert.success(i18n.t("recipe.added-to-timeline"));
|
||||||
|
}
|
||||||
|
|
||||||
|
resetMadeThisForm();
|
||||||
context.emit("eventCreated", newEvent);
|
context.emit("eventCreated", newEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@
|
||||||
<BaseButton
|
<BaseButton
|
||||||
v-if="canSubmit"
|
v-if="canSubmit"
|
||||||
type="submit"
|
type="submit"
|
||||||
:disabled="submitDisabled"
|
:disabled="submitDisabled || loading"
|
||||||
@click="submitEvent"
|
@click="submitEvent"
|
||||||
>
|
>
|
||||||
{{ submitText }}
|
{{ submitText }}
|
||||||
|
|
|
@ -579,6 +579,10 @@
|
||||||
"made-this": "I Made This",
|
"made-this": "I Made This",
|
||||||
"how-did-it-turn-out": "How did it turn out?",
|
"how-did-it-turn-out": "How did it turn out?",
|
||||||
"user-made-this": "{user} made this",
|
"user-made-this": "{user} made this",
|
||||||
|
"added-to-timeline": "Added to timeline",
|
||||||
|
"failed-to-add-to-timeline": "Failed to add to timeline",
|
||||||
|
"failed-to-update-recipe": "Failed to update recipe",
|
||||||
|
"added-to-timeline-but-failed-to-add-image": "Added to timeline, but failed to add image",
|
||||||
"api-extras-description": "Recipes extras are a key feature of the Mealie API. They allow you to create custom JSON key/value pairs within a recipe, to reference from 3rd party applications. You can use these keys to provide information, for example to trigger automations or custom messages to relay to your desired device.",
|
"api-extras-description": "Recipes extras are a key feature of the Mealie API. They allow you to create custom JSON key/value pairs within a recipe, to reference from 3rd party applications. You can use these keys to provide information, for example to trigger automations or custom messages to relay to your desired device.",
|
||||||
"message-key": "Message Key",
|
"message-key": "Message Key",
|
||||||
"parse": "Parse",
|
"parse": "Parse",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue