Refactor/composables-folder (#787)
* move api clients and rename * organize recipes composables * rewrite useRecipeContext * refactor(frontend): ♻️ abstract common ingredient functionality. * feat(frontend): ✨ add scale, and back to recipe button + hide ingredients if none * update regex to mach 11. instead of just 1. * minor UX improvements Co-authored-by: Hayden K <hay-kot@pm.me>
This commit is contained in:
parent
095d3bda3f
commit
788e176b16
68 changed files with 330 additions and 245 deletions
|
@ -71,7 +71,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
export default {
|
||||
props: {
|
||||
slug: {
|
||||
|
@ -88,7 +88,7 @@ export default {
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -18,8 +18,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { useStaticRoutes } from "~/composables/api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useStaticRoutes, useUserApi } from "~/composables/api";
|
||||
export default {
|
||||
props: {
|
||||
tiny: {
|
||||
|
@ -52,7 +51,7 @@ export default {
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const { recipeImage, recipeSmallImage, recipeTinyImage } = useStaticRoutes();
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import RecipeFavoriteBadge from "./RecipeFavoriteBadge";
|
||||
import RecipeContextMenu from "./RecipeContextMenu";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
export default defineComponent({
|
||||
components: {
|
||||
RecipeFavoriteBadge,
|
||||
|
@ -104,7 +104,7 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -103,7 +103,7 @@
|
|||
<script>
|
||||
import RecipeCard from "./RecipeCard";
|
||||
import RecipeCardMobile from "./RecipeCardMobile";
|
||||
import { useSorter } from "~/composables/use-recipes";
|
||||
import { useSorter } from "~/composables/recipes";
|
||||
const SORT_EVENT = "sort";
|
||||
|
||||
export default {
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
<script>
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
const CREATED_ITEM_EVENT = "created-item";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
|
@ -58,7 +58,7 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -44,8 +44,8 @@
|
|||
|
||||
<script>
|
||||
import RecipeCategoryTagDialog from "./RecipeCategoryTagDialog";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useTags, useCategories } from "~/composables/use-tags-categories";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useTags, useCategories } from "~/composables/recipes";
|
||||
const MOUNTED_EVENT = "mounted";
|
||||
export default {
|
||||
components: {
|
||||
|
@ -91,7 +91,7 @@ export default {
|
|||
},
|
||||
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const { allTags, useAsyncGetAll: getAllTags } = useTags();
|
||||
const { allCategories, useAsyncGetAll: getAllCategories } = useCategories();
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
const NEW_COMMENT_EVENT = "new-comment";
|
||||
const UPDATE_COMMENT_EVENT = "update-comment";
|
||||
export default {
|
||||
|
@ -65,7 +65,7 @@ export default {
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRefs, useContext, useRouter } from "@nuxtjs/composition-api";
|
||||
import { useClipboard, useShare } from "@vueuse/core";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
|
||||
export interface ContextMenuIncludes {
|
||||
|
@ -147,7 +147,7 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup(props, context) {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
import { computed, defineComponent, onMounted, ref } from "@nuxtjs/composition-api";
|
||||
import RecipeChip from "./RecipeChips.vue";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { UserOut } from "~/types/api-types/user";
|
||||
|
||||
const INPUT_EVENT = "input";
|
||||
|
@ -114,7 +114,7 @@ export default defineComponent({
|
|||
|
||||
// ============
|
||||
// Group Members
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const members = ref<UserOut[] | null[]>([]);
|
||||
|
||||
async function refreshMembers() {
|
||||
|
|
|
@ -82,7 +82,7 @@ export default defineComponent({
|
|||
.join("\n");
|
||||
}
|
||||
|
||||
const numberedLineRegex = /\d[.):] /gm;
|
||||
const numberedLineRegex = /\d+[.):] /gm;
|
||||
|
||||
function splitByNumberedLine() {
|
||||
// Split inputText by numberedLineRegex
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
<script>
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
slug: {
|
||||
|
@ -39,7 +39,7 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
|
||||
<script>
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
const REFRESH_EVENT = "refresh";
|
||||
const UPLOAD_EVENT = "upload";
|
||||
export default defineComponent({
|
||||
|
@ -52,7 +52,7 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -95,8 +95,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRefs } from "@nuxtjs/composition-api";
|
||||
import { useFoods } from "~/composables/use-recipe-foods";
|
||||
import { useUnits } from "~/composables/use-recipe-units";
|
||||
import { useFoods, useUnits } from "~/composables/recipes";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div v-if="value && value.length > 0">
|
||||
<div class="d-flex justify-start">
|
||||
<h2 class="mb-4 mt-1">{{ $t("recipe.ingredients") }}</h2>
|
||||
<AppButtonCopy btn-class="ml-auto" :copy-text="ingredientCopyText" />
|
||||
<AppButtonCopy btn-class="ml-auto" :copy-text="ingredientCopyText" />
|
||||
</div>
|
||||
<div>
|
||||
<div v-for="(ingredient, index) in value" :key="'ingredient' + index">
|
||||
|
@ -11,7 +11,10 @@
|
|||
<v-list-item dense @click="toggleChecked(index)">
|
||||
<v-checkbox hide-details :value="checked[index]" class="pt-0 my-auto py-auto" color="secondary"> </v-checkbox>
|
||||
<v-list-item-content>
|
||||
<VueMarkdown class="ma-0 pa-0 text-subtitle-1 dense-markdown" :source="parseIngredientText(ingredient)">
|
||||
<VueMarkdown
|
||||
class="ma-0 pa-0 text-subtitle-1 dense-markdown"
|
||||
:source="parseIngredientText(ingredient, disableAmount, scale)"
|
||||
>
|
||||
</VueMarkdown>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
@ -23,7 +26,7 @@
|
|||
<script>
|
||||
import { computed, defineComponent } from "@nuxtjs/composition-api";
|
||||
import VueMarkdown from "@adapttive/vue-markdown";
|
||||
import { useFraction } from "@/composables/use-fraction";
|
||||
import { parseIngredientText } from "~/composables/recipes";
|
||||
export default defineComponent({
|
||||
components: {
|
||||
VueMarkdown,
|
||||
|
@ -43,37 +46,10 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { frac } = useFraction();
|
||||
|
||||
function parseIngredientText(ingredient) {
|
||||
if (props.disableAmount) {
|
||||
return ingredient.note;
|
||||
}
|
||||
|
||||
const { quantity, food, unit, note } = ingredient;
|
||||
|
||||
let return_qty = "";
|
||||
if (unit?.fraction) {
|
||||
const fraction = frac(quantity * props.scale, 10, true);
|
||||
if (fraction[0] !== undefined && fraction[0] > 0) {
|
||||
return_qty += fraction[0];
|
||||
}
|
||||
|
||||
if (fraction[1] > 0) {
|
||||
return_qty += ` <sup>${fraction[1]}</sup>⁄<sub>${fraction[2]}</sub>`;
|
||||
}
|
||||
} else {
|
||||
return_qty = quantity * props.scale;
|
||||
}
|
||||
|
||||
return `${return_qty} ${unit?.name || " "} ${food?.name || " "} ${note}`;
|
||||
}
|
||||
|
||||
const ingredientCopyText = computed(() => {
|
||||
// Returns a string of all ingredients in markdown list format -[ ]
|
||||
return props.value
|
||||
.map((ingredient) => {
|
||||
return `- [ ] ${parseIngredientText(ingredient)}`;
|
||||
return `- [ ] ${parseIngredientText(ingredient, props.disableAmount, props.scale)}`;
|
||||
})
|
||||
.join("\n");
|
||||
});
|
||||
|
|
|
@ -17,13 +17,31 @@
|
|||
</p>
|
||||
<v-divider class="mb-4"></v-divider>
|
||||
<v-checkbox
|
||||
v-for="ing in ingredients"
|
||||
v-for="ing in unusedIngredients"
|
||||
:key="ing.referenceId"
|
||||
v-model="activeRefs"
|
||||
:label="ing.note"
|
||||
:value="ing.referenceId"
|
||||
class="mb-n2 mt-n2"
|
||||
></v-checkbox>
|
||||
>
|
||||
<template #label>
|
||||
<div v-html="parseIngredientText(ing, disableAmount)"></div>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
|
||||
<template v-if="usedIngredients.length > 0">
|
||||
<h4 class="py-3 ml-1">Linked to other step</h4>
|
||||
<v-checkbox
|
||||
v-for="ing in usedIngredients"
|
||||
:key="ing.referenceId"
|
||||
v-model="activeRefs"
|
||||
:value="ing.referenceId"
|
||||
class="mb-n2 mt-n2"
|
||||
>
|
||||
<template #label>
|
||||
<div v-html="parseIngredientText(ing, disableAmount)"></div>
|
||||
</template>
|
||||
</v-checkbox>
|
||||
</template>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider></v-divider>
|
||||
|
@ -111,17 +129,16 @@
|
|||
<v-card-text v-if="edit">
|
||||
<v-textarea :key="'instructions' + index" v-model="value[index]['text']" auto-grow dense rows="4">
|
||||
</v-textarea>
|
||||
<div v-for="ing in step.ingredientReferences" :key="ing.referenceId">
|
||||
{{ getIngredientByRefId(ing.referenceId).note }}
|
||||
</div>
|
||||
<div
|
||||
v-for="ing in step.ingredientReferences"
|
||||
:key="ing.referenceId"
|
||||
v-html="getIngredientByRefId(ing.referenceId)"
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-expand-transition>
|
||||
<div v-show="!isChecked(index) && !edit" class="m-0 p-0">
|
||||
<v-card-text>
|
||||
<VueMarkdown :source="step.text"> </VueMarkdown>
|
||||
<div v-for="ing in step.ingredientReferences" :key="ing.referenceId">
|
||||
{{ getIngredientByRefId(ing.referenceId).note }}
|
||||
</div>
|
||||
</v-card-text>
|
||||
</div>
|
||||
</v-expand-transition>
|
||||
|
@ -138,6 +155,7 @@ import draggable from "vuedraggable";
|
|||
import VueMarkdown from "@adapttive/vue-markdown";
|
||||
import { ref, toRefs, reactive, defineComponent, watch, onMounted } from "@nuxtjs/composition-api";
|
||||
import { RecipeStep, IngredientToStepRef, RecipeIngredient } from "~/types/api-types/recipe";
|
||||
import { parseIngredientText } from "~/composables/recipes";
|
||||
|
||||
interface MergerHistory {
|
||||
target: number;
|
||||
|
@ -164,12 +182,18 @@ export default defineComponent({
|
|||
type: Array as () => RecipeIngredient[],
|
||||
default: () => [],
|
||||
},
|
||||
disableAmount: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
setup(props, context) {
|
||||
const state = reactive({
|
||||
dialog: false,
|
||||
disabledSteps: [] as number[],
|
||||
unusedIngredients: [] as RecipeIngredient[],
|
||||
usedIngredients: [] as RecipeIngredient[],
|
||||
});
|
||||
|
||||
const showTitleEditor = ref<boolean[]>([]);
|
||||
|
@ -245,6 +269,7 @@ export default defineComponent({
|
|||
const activeText = ref("");
|
||||
|
||||
function openDialog(idx: number, refs: IngredientToStepRef[], text: string) {
|
||||
setUsedIngredients();
|
||||
activeText.value = text;
|
||||
activeIndex.value = idx;
|
||||
state.dialog = true;
|
||||
|
@ -261,6 +286,24 @@ export default defineComponent({
|
|||
state.dialog = false;
|
||||
}
|
||||
|
||||
function setUsedIngredients() {
|
||||
const usedRefs: { [key: string]: boolean } = {};
|
||||
|
||||
props.value.forEach((element) => {
|
||||
element.ingredientReferences.forEach((ref) => {
|
||||
usedRefs[ref.referenceId] = true;
|
||||
});
|
||||
});
|
||||
|
||||
state.usedIngredients = props.ingredients.filter((ing) => {
|
||||
return ing.referenceId in usedRefs;
|
||||
});
|
||||
|
||||
state.unusedIngredients = props.ingredients.filter((ing) => {
|
||||
return !(ing.referenceId in usedRefs);
|
||||
});
|
||||
}
|
||||
|
||||
function autoSetReferences() {
|
||||
// Ingore matching blacklisted words when auto-linking - This is kind of a cludgey implementation. We're blacklisting common words but
|
||||
// other common phrases trigger false positives and I'm not sure how else to approach this. In the future I maybe look at looking directly
|
||||
|
@ -294,10 +337,9 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
props.ingredients.forEach((ingredient) => {
|
||||
if (
|
||||
ingredient.note.toLowerCase().includes(" " + word) &&
|
||||
!activeRefs.value.includes(ingredient.referenceId)
|
||||
) {
|
||||
const searchText = parseIngredientText(ingredient, props.disableAmount);
|
||||
|
||||
if (searchText.toLowerCase().includes(" " + word) && !activeRefs.value.includes(ingredient.referenceId)) {
|
||||
console.info("Word Matched", `'${word}'`, ingredient.note);
|
||||
activeRefs.value.push(ingredient.referenceId);
|
||||
}
|
||||
|
@ -306,7 +348,11 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
function getIngredientByRefId(refId: String) {
|
||||
return props.ingredients.find((ing) => ing.referenceId === refId) || "";
|
||||
const ing = props.ingredients.find((ing) => ing.referenceId === refId) || "";
|
||||
if (ing === "") {
|
||||
return "";
|
||||
}
|
||||
return parseIngredientText(ing, props.disableAmount);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
|
@ -365,6 +411,7 @@ export default defineComponent({
|
|||
toggleShowTitle,
|
||||
updateIndex,
|
||||
autoSetReferences,
|
||||
parseIngredientText,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
<script>
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
emitOnly: {
|
||||
|
@ -43,7 +43,7 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
// import AppButtonUpload from "@/components/UI/Buttons/AppButtonUpload.vue";
|
||||
import { defineComponent, ref } from "@nuxtjs/composition-api";
|
||||
import { fieldTypes } from "~/composables/forms";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
|
||||
export default defineComponent({
|
||||
|
@ -160,7 +160,7 @@ export default defineComponent({
|
|||
const domImportFromUrlDialog = ref(null);
|
||||
const domImportFromUrlForm = ref<VForm | null>(null);
|
||||
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return {
|
||||
domCreateDialog,
|
||||
|
|
|
@ -68,8 +68,8 @@ export default {
|
|||
this.show = true;
|
||||
const copyText = this.copyText;
|
||||
navigator.clipboard.writeText(copyText).then(
|
||||
() => console.log("Copied", copyText),
|
||||
() => console.log("Copied Failed", copyText)
|
||||
() => console.log(`Copied\n${copyText}`),
|
||||
() => console.log(`Copied Failed\n${copyText}`)
|
||||
);
|
||||
setTimeout(() => {
|
||||
this.toggleBlur();
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
const UPLOAD_EVENT = "uploaded";
|
||||
export default {
|
||||
props: {
|
||||
|
@ -45,7 +45,7 @@ export default {
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
export default {
|
||||
name: "BaseButton",
|
||||
props: {
|
||||
|
@ -107,7 +107,7 @@ export default {
|
|||
},
|
||||
},
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
return { api };
|
||||
},
|
||||
|
|
|
@ -59,7 +59,7 @@ export const useAdminApi = function (): AdminAPI {
|
|||
return new AdminAPI(requests);
|
||||
};
|
||||
|
||||
export const useApiSingleton = function (): Api {
|
||||
export const useUserApi = function (): Api {
|
||||
const { $axios } = useContext();
|
||||
const requests = getRequests($axios);
|
||||
|
|
@ -1 +1,2 @@
|
|||
export { useStaticRoutes } from "./static-routes";
|
||||
export { useAdminApi, useUserApi } from "./api-client";
|
||||
|
|
7
frontend/composables/recipes/index.ts
Normal file
7
frontend/composables/recipes/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export { useFraction } from "./use-fraction";
|
||||
export { useRecipe } from "./use-recipe";
|
||||
export { useFoods } from "./use-recipe-foods";
|
||||
export { useUnits } from "./use-recipe-units";
|
||||
export { useRecipes, recentRecipes, allRecipes, useLazyRecipes, useSorter } from "./use-recipes";
|
||||
export { useTags, useCategories, allCategories, allTags } from "./use-tags-categories";
|
||||
export { parseIngredientText } from "./use-recipe-ingredients";
|
|
@ -1,12 +1,12 @@
|
|||
import { useAsync, ref, reactive, Ref } from "@nuxtjs/composition-api";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useAsyncKey } from "../use-utils";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { Food } from "~/api/class-interfaces/recipe-foods";
|
||||
|
||||
let foodStore: Ref<Food[] | null> | null = null;
|
||||
|
||||
export const useFoods = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
const deleteTargetId = ref(0);
|
||||
const validForm = ref(true);
|
28
frontend/composables/recipes/use-recipe-ingredients.ts
Normal file
28
frontend/composables/recipes/use-recipe-ingredients.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { useFraction } from "./use-fraction";
|
||||
import { RecipeIngredient } from "~/types/api-types/recipe";
|
||||
|
||||
const { frac } = useFraction();
|
||||
|
||||
export function parseIngredientText(ingredient: RecipeIngredient, disableAmount: boolean, scale: number = 1): string {
|
||||
if (disableAmount) {
|
||||
return ingredient.note;
|
||||
}
|
||||
|
||||
const { quantity, food, unit, note } = ingredient;
|
||||
|
||||
let returnQty = "";
|
||||
if (unit?.fraction) {
|
||||
const fraction = frac(quantity * scale, 10, true);
|
||||
if (fraction[0] !== undefined && fraction[0] > 0) {
|
||||
returnQty += fraction[0];
|
||||
}
|
||||
|
||||
if (fraction[1] > 0) {
|
||||
returnQty += ` <sup>${fraction[1]}</sup>⁄<sub>${fraction[2]}</sub>`;
|
||||
}
|
||||
} else {
|
||||
returnQty = (quantity * scale).toString();
|
||||
}
|
||||
|
||||
return `${returnQty} ${unit?.name || " "} ${food?.name || " "} ${note}`.replace(/ {2,}/g, " ");
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
import { useAsync, ref, reactive, Ref } from "@nuxtjs/composition-api";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useAsyncKey } from "../use-utils";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { Unit } from "~/api/class-interfaces/recipe-units";
|
||||
|
||||
let unitStore: Ref<Unit[] | null> | null = null;
|
||||
|
||||
export const useUnits = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
const deleteTargetId = ref(0);
|
||||
const validForm = ref(true);
|
47
frontend/composables/recipes/use-recipe.ts
Normal file
47
frontend/composables/recipes/use-recipe.ts
Normal file
|
@ -0,0 +1,47 @@
|
|||
import { ref, onMounted } from "@nuxtjs/composition-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
|
||||
export const useRecipe = function (slug: string, eager: boolean = true) {
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
|
||||
const recipe = ref<Recipe | null>(null);
|
||||
|
||||
async function fetchRecipe() {
|
||||
loading.value = true;
|
||||
const { data } = await api.recipes.getOne(slug);
|
||||
loading.value = false;
|
||||
if (data) {
|
||||
recipe.value = data;
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteRecipe() {
|
||||
loading.value = true;
|
||||
const { data } = await api.recipes.deleteOne(slug);
|
||||
loading.value = false;
|
||||
return data;
|
||||
}
|
||||
|
||||
async function updateRecipe(recipe: Recipe) {
|
||||
loading.value = true;
|
||||
const { data } = await api.recipes.updateOne(slug, recipe);
|
||||
loading.value = false;
|
||||
return data;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (eager) {
|
||||
fetchRecipe();
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
recipe,
|
||||
loading,
|
||||
fetchRecipe,
|
||||
deleteRecipe,
|
||||
updateRecipe,
|
||||
};
|
||||
};
|
|
@ -1,7 +1,7 @@
|
|||
import { useAsync, ref } from "@nuxtjs/composition-api";
|
||||
import { set } from "@vueuse/core";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useAsyncKey } from "../use-utils";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
|
||||
export const allRecipes = ref<Recipe[] | null>([]);
|
||||
|
@ -58,7 +58,7 @@ export const useSorter = () => {
|
|||
};
|
||||
|
||||
export const useLazyRecipes = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const recipes = ref<Recipe[] | null>([]);
|
||||
|
||||
|
@ -78,7 +78,7 @@ export const useLazyRecipes = function () {
|
|||
};
|
||||
|
||||
export const useRecipes = (all = false, fetchRecipes = true) => {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
// recipes is non-reactive!!
|
||||
const { recipes, start, end } = (() => {
|
|
@ -1,6 +1,6 @@
|
|||
import { Ref, ref, useAsync } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "./use-api";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useUserApi } from "../api";
|
||||
import { useAsyncKey } from "../use-utils";
|
||||
import { CategoriesAPI, Category } from "~/api/class-interfaces/categories";
|
||||
import { Tag, TagsAPI } from "~/api/class-interfaces/tags";
|
||||
|
||||
|
@ -45,14 +45,14 @@ function baseTagsCategories(reference: Ref<Category[] | null> | Ref<Tag[] | null
|
|||
}
|
||||
|
||||
export const useTags = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
return {
|
||||
allTags,
|
||||
...baseTagsCategories(allTags, api.tags),
|
||||
};
|
||||
};
|
||||
export const useCategories = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
return {
|
||||
allCategories,
|
||||
...baseTagsCategories(allCategories, api.categories),
|
|
@ -2,7 +2,7 @@ import { useAsync, ref, reactive } from "@nuxtjs/composition-api";
|
|||
import { set } from "@vueuse/core";
|
||||
import { toastLoading, loader } from "./use-toast";
|
||||
import { AllBackups, ImportBackup } from "~/api/class-interfaces/backups";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
|
||||
const backups = ref<AllBackups>({
|
||||
imports: [],
|
||||
|
@ -32,7 +32,7 @@ function optionsFactory() {
|
|||
}
|
||||
|
||||
export const useBackups = function (fetch = true) {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const backupOptions = reactive(optionsFactory());
|
||||
const deleteTarget = ref("");
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { useAsync, ref, reactive, Ref } from "@nuxtjs/composition-api";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { CookBook } from "~/api/class-interfaces/group-cookbooks";
|
||||
|
||||
let cookbookStore: Ref<CookBook[] | null> | null = null;
|
||||
|
||||
export const useCookbook = function () {
|
||||
function getOne(id: string | number) {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const units = useAsync(async () => {
|
||||
const { data } = await api.cookbooks.getOne(id);
|
||||
|
@ -22,7 +22,7 @@ export const useCookbook = function () {
|
|||
};
|
||||
|
||||
export const useCookbooks = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
const deleteTargetId = ref(0);
|
||||
const validForm = ref(true);
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { useAsync, ref } from "@nuxtjs/composition-api";
|
||||
import { addDays, subDays, format } from "date-fns";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { CreateMealPlan, UpdateMealPlan } from "~/api/class-interfaces/group-mealplan";
|
||||
|
||||
export const useMealplans = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
const validForm = ref(true);
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { useAsync, ref } from "@nuxtjs/composition-api";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { GroupWebhook } from "~/api/class-interfaces/group-webhooks";
|
||||
|
||||
export const useGroupWebhooks = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
const validForm = ref(true);
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { useAsync, ref } from "@nuxtjs/composition-api";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { CreateGroup } from "~/api/class-interfaces/groups";
|
||||
|
||||
export const useGroupSelf = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const actions = {
|
||||
get() {
|
||||
|
@ -35,7 +35,7 @@ export const useGroupSelf = function () {
|
|||
};
|
||||
|
||||
export const useGroupCategories = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const actions = {
|
||||
getAll() {
|
||||
|
@ -61,7 +61,7 @@ export const useGroupCategories = function () {
|
|||
};
|
||||
|
||||
export const useGroups = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
|
||||
function getAllGroups() {
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import { useAsync, ref } from "@nuxtjs/composition-api";
|
||||
import { CreateEventNotification } from "@/api/class-interfaces/event-notifications";
|
||||
import { useAsyncKey } from "./use-utils";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { CreateEventNotification } from "@/api/class-interfaces/event-notifications";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
|
||||
const notificationTypes = ["General", "Discord", "Gotify", "Pushover", "Home Assistant"];
|
||||
|
||||
|
||||
export const useNotifications = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
|
||||
const createNotificationData = ref<CreateEventNotification>({
|
||||
|
@ -23,7 +22,7 @@ export const useNotifications = function () {
|
|||
notificationUrl: "",
|
||||
});
|
||||
|
||||
const deleteTarget = ref(0)
|
||||
const deleteTarget = ref(0);
|
||||
|
||||
function getNotifications() {
|
||||
loading.value = true;
|
||||
|
@ -63,13 +62,13 @@ export const useNotifications = function () {
|
|||
}
|
||||
|
||||
async function testById(id: number) {
|
||||
const {data} = await api.notifications.testNotification(id, null)
|
||||
console.log(data)
|
||||
const { data } = await api.notifications.testNotification(id, null);
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
async function testByUrl(testUrl: string) {
|
||||
const {data} = await api.notifications.testNotification(null, testUrl)
|
||||
console.log(data)
|
||||
const { data } = await api.notifications.testNotification(null, testUrl);
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
const notifications = getNotifications();
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import { useAsync, ref } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
|
||||
export const useRecipeContext = function () {
|
||||
const api = useApiSingleton();
|
||||
const loading = ref(false);
|
||||
|
||||
function getBySlug(slug: string) {
|
||||
loading.value = true;
|
||||
const recipe = useAsync(async () => {
|
||||
const { data } = await api.recipes.getOne(slug);
|
||||
return data;
|
||||
}, slug);
|
||||
|
||||
loading.value = false;
|
||||
|
||||
return recipe;
|
||||
}
|
||||
|
||||
async function fetchRecipe(slug: string) {
|
||||
loading.value = true;
|
||||
const { data } = await api.recipes.getOne(slug);
|
||||
loading.value = false;
|
||||
return data;
|
||||
}
|
||||
|
||||
async function deleteRecipe(slug: string) {
|
||||
loading.value = true;
|
||||
const { data } = await api.recipes.deleteOne(slug);
|
||||
loading.value = false;
|
||||
return data;
|
||||
}
|
||||
|
||||
async function updateRecipe(slug: string, recipe: Recipe) {
|
||||
loading.value = true;
|
||||
const { data } = await api.recipes.updateOne(slug, recipe);
|
||||
loading.value = false;
|
||||
return data;
|
||||
}
|
||||
|
||||
return { loading, getBySlug, deleteRecipe, updateRecipe, fetchRecipe };
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
import { useAsync, ref } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { UserIn, UserOut } from "~/types/api-types/user";
|
||||
|
||||
/*
|
||||
|
@ -9,7 +9,7 @@ to control whether the object is substantiated... but some of the others rely on
|
|||
*/
|
||||
|
||||
export const useAllUsers = function () {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
|
||||
function getAllUsers() {
|
||||
|
@ -37,7 +37,7 @@ export const useAllUsers = function () {
|
|||
};
|
||||
|
||||
export const useUser = function (refreshFunc: CallableFunction | null = null) {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const loading = ref(false);
|
||||
|
||||
function getUser(id: string) {
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
export const useAsyncKey = function () {
|
||||
return String(Date.now());
|
||||
};
|
||||
|
||||
export function uuid4() {
|
||||
// @ts-ignore
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
|
||||
(c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
const max = 1000000;
|
||||
|
||||
export function uniqueId() {
|
||||
return Date.now() + Math.random() * max;
|
||||
}
|
||||
|
||||
export function uuid4() {
|
||||
// @ts-ignore
|
||||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
|
||||
(c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
|
||||
);
|
||||
}
|
|
@ -42,7 +42,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref } from "@nuxtjs/composition-api";
|
||||
import { ServerTask } from "~/api/types/server-task";
|
||||
import { useAdminApi } from "~/composables/use-api";
|
||||
import { useAdminApi } from "~/composables/api";
|
||||
|
||||
export default defineComponent({
|
||||
layout: "admin",
|
||||
|
|
|
@ -92,14 +92,14 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, useAsync } from "@nuxtjs/composition-api";
|
||||
import AdminEventViewer from "@/components/Domain/Admin/AdminEventViewer.vue";
|
||||
import { useAdminApi, useApiSingleton } from "~/composables/use-api";
|
||||
import { useAdminApi, useUserApi } from "~/composables/api";
|
||||
import { useAsyncKey } from "~/composables/use-utils";
|
||||
|
||||
export default defineComponent({
|
||||
components: { AdminEventViewer },
|
||||
layout: "admin",
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const adminApi = useAdminApi();
|
||||
|
||||
|
|
|
@ -72,14 +72,14 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, ref } from "@nuxtjs/composition-api";
|
||||
import { fieldTypes } from "~/composables/forms";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useGroups } from "~/composables/use-groups";
|
||||
import { useUser, useAllUsers } from "~/composables/use-user";
|
||||
|
||||
export default defineComponent({
|
||||
layout: "admin",
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const refUserDialog = ref();
|
||||
|
||||
const { groups } = useGroups();
|
||||
|
|
|
@ -69,12 +69,12 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRefs } from "@nuxtjs/composition-api";
|
||||
import { Confidence, Parser } from "~/api/class-interfaces/recipes";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
|
||||
export default defineComponent({
|
||||
layout: "admin",
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
|
|
|
@ -102,7 +102,7 @@ import {
|
|||
useContext,
|
||||
} from "@nuxtjs/composition-api";
|
||||
import { CheckAppConfig } from "~/api/admin/admin-about";
|
||||
import { useAdminApi, useApiSingleton } from "~/composables/use-api";
|
||||
import { useAdminApi, useUserApi } from "~/composables/api";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
import { useAsyncKey } from "~/composables/use-utils";
|
||||
|
||||
|
@ -130,7 +130,7 @@ export default defineComponent({
|
|||
isSiteSecure: false,
|
||||
});
|
||||
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const adminApi = useAdminApi();
|
||||
onMounted(async () => {
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, ref, computed } from "@nuxtjs/composition-api";
|
||||
import { useFoods } from "~/composables/use-recipe-foods";
|
||||
import { useFoods } from "~/composables/recipes";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
export default defineComponent({
|
||||
layout: "admin",
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, ref, computed } from "@nuxtjs/composition-api";
|
||||
import { useUnits } from "~/composables/use-recipe-units";
|
||||
import { useUnits } from "~/composables/recipes";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
export default defineComponent({
|
||||
layout: "admin",
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, toRefs, reactive } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
export default defineComponent({
|
||||
layout: "basic",
|
||||
|
@ -47,7 +47,7 @@ export default defineComponent({
|
|||
error: false,
|
||||
});
|
||||
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
async function requestLink() {
|
||||
state.loading = true;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
|
||||
import { useRecipes, recentRecipes } from "~/composables/use-recipes";
|
||||
import { useRecipes, recentRecipes } from "~/composables/recipes";
|
||||
import { useStaticRoutes } from "~/composables/api";
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
@ -152,7 +152,7 @@ import { isSameDay, addDays, subDays, parseISO, format } from "date-fns";
|
|||
import { SortableEvent } from "sortablejs"; // eslint-disable-line
|
||||
import draggable from "vuedraggable";
|
||||
import { useMealplans } from "~/composables/use-group-mealplan";
|
||||
import { useRecipes, allRecipes } from "~/composables/use-recipes";
|
||||
import { useRecipes, allRecipes } from "~/composables/recipes";
|
||||
import RecipeCardImage from "~/components/Domain/Recipe/RecipeCardImage.vue";
|
||||
|
||||
export default defineComponent({
|
||||
|
|
|
@ -8,12 +8,30 @@
|
|||
<v-card-title>
|
||||
<h1 class="headline">{{ recipe.name }}</h1>
|
||||
</v-card-title>
|
||||
|
||||
<v-stepper v-model="activeStep" flat>
|
||||
<v-toolbar class="ma-1 elevation-2 rounded">
|
||||
<v-toolbar-title class="headline">
|
||||
Step {{ activeStep }} of {{ recipe.recipeInstructions.length }}</v-toolbar-title
|
||||
>
|
||||
</v-toolbar>
|
||||
<div class="d-flex mt-3 px-2">
|
||||
<BaseButton color="primary" @click="$router.go(-1)">
|
||||
<template #icon> {{ $globals.icons.arrowLeftBold }}</template>
|
||||
To Recipe
|
||||
</BaseButton>
|
||||
<v-btn rounded icon color="primary" class="ml-auto" small @click="scale > 1 ? scale-- : null">
|
||||
<v-icon>
|
||||
{{ $globals.icons.minus }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
<v-btn rounded color="primary" small> Scale: {{ scale }} </v-btn>
|
||||
<v-btn rounded icon color="primary" small @click="scale++">
|
||||
<v-icon>
|
||||
{{ $globals.icons.createAlt }}
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-stepper-items>
|
||||
<template v-for="(step, index) in recipe.recipeInstructions">
|
||||
<v-stepper-content :key="index + 1 + '-content'" :step="index + 1" class="pa-0 mt-2 elevation-0">
|
||||
|
@ -21,11 +39,17 @@
|
|||
<v-card-text>
|
||||
<h2 class="mb-4">{{ $t("recipe.instructions") }}</h2>
|
||||
<VueMarkdown :source="step.text"> </VueMarkdown>
|
||||
<v-divider></v-divider>
|
||||
<h2 class="mb-4 mt-4">{{ $t("recipe.ingredients") }}</h2>
|
||||
<div v-for="ing in step.ingredientReferences" :key="ing.referenceId">
|
||||
{{ getIngredientByRefId(ing.referenceId).note }}
|
||||
</div>
|
||||
<template v-if="step.ingredientReferences.length > 0">
|
||||
<v-divider></v-divider>
|
||||
<div>
|
||||
<h2 class="mb-4 mt-4">{{ $t("recipe.ingredients") }}</h2>
|
||||
<div
|
||||
v-for="ing in step.ingredientReferences"
|
||||
:key="ing.referenceId"
|
||||
v-html="getIngredientByRefId(ing.referenceId)"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-card-actions class="justify-center">
|
||||
|
@ -33,6 +57,7 @@
|
|||
<template #icon> {{ $globals.icons.arrowLeftBold }}</template>
|
||||
Back
|
||||
</BaseButton>
|
||||
|
||||
<BaseButton
|
||||
icon-right
|
||||
:disabled="index + 1 == recipe.recipeInstructions.length"
|
||||
|
@ -55,25 +80,35 @@ import { defineComponent, useRoute, ref } from "@nuxtjs/composition-api";
|
|||
// @ts-ignore
|
||||
import VueMarkdown from "@adapttive/vue-markdown";
|
||||
import { useStaticRoutes } from "~/composables/api";
|
||||
import { useRecipeContext } from "~/composables/use-recipe-context";
|
||||
import { parseIngredientText, useRecipe } from "~/composables/recipes";
|
||||
|
||||
export default defineComponent({
|
||||
components: { VueMarkdown },
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const slug = route.value.params.slug;
|
||||
const activeStep = ref(1);
|
||||
const scale = ref(1);
|
||||
|
||||
const { getBySlug } = useRecipeContext();
|
||||
const { recipe } = useRecipe(slug);
|
||||
|
||||
const { recipeImage } = useStaticRoutes();
|
||||
|
||||
const recipe = getBySlug(slug);
|
||||
|
||||
function getIngredientByRefId(refId: String) {
|
||||
return recipe.value?.recipeIngredient.find((ing) => ing.referenceId === refId) || "";
|
||||
if (!recipe.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ing = recipe?.value.recipeIngredient.find((ing) => ing.referenceId === refId) || "";
|
||||
if (ing === "") {
|
||||
return "";
|
||||
}
|
||||
|
||||
return parseIngredientText(ing, recipe?.value?.settings?.disableAmount || false, scale.value);
|
||||
}
|
||||
|
||||
return {
|
||||
scale,
|
||||
getIngredientByRefId,
|
||||
activeStep,
|
||||
slug,
|
||||
|
|
|
@ -233,6 +233,7 @@
|
|||
<RecipeInstructions
|
||||
v-model="recipe.recipeInstructions"
|
||||
:ingredients="recipe.recipeIngredient"
|
||||
:disable-amount="recipe.settings.disableAmount"
|
||||
:edit="form"
|
||||
/>
|
||||
<div v-if="form" class="d-flex">
|
||||
|
@ -289,9 +290,9 @@ import VueMarkdown from "@adapttive/vue-markdown";
|
|||
import draggable from "vuedraggable";
|
||||
import RecipeCategoryTagSelector from "@/components/Domain/Recipe/RecipeCategoryTagSelector.vue";
|
||||
import RecipeDialogBulkAdd from "@/components/Domain/Recipe//RecipeDialogBulkAdd.vue";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi, useStaticRoutes } from "~/composables/api";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
import { useRecipeContext } from "~/composables/use-recipe-context";
|
||||
import { useRecipe } from "~/composables/recipes";
|
||||
import RecipeActionMenu from "~/components/Domain/Recipe/RecipeActionMenu.vue";
|
||||
import RecipeChips from "~/components/Domain/Recipe/RecipeChips.vue";
|
||||
import RecipeIngredients from "~/components/Domain/Recipe/RecipeIngredients.vue";
|
||||
|
@ -307,8 +308,7 @@ import RecipeIngredientEditor from "~/components/Domain/Recipe/RecipeIngredientE
|
|||
import RecipeIngredientParserMenu from "~/components/Domain/Recipe/RecipeIngredientParserMenu.vue";
|
||||
import RecipePrintView from "~/components/Domain/Recipe/RecipePrintView.vue";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
import { useStaticRoutes } from "~/composables/api";
|
||||
import { uuid4 } from "~/composables/use-uuid";
|
||||
import { uuid4 } from "~/composables/use-utils";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
|
@ -335,7 +335,7 @@ export default defineComponent({
|
|||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const slug = route.value.params.slug;
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const state = reactive({
|
||||
form: false,
|
||||
|
@ -352,15 +352,13 @@ export default defineComponent({
|
|||
},
|
||||
});
|
||||
|
||||
const { getBySlug, loading, fetchRecipe } = useRecipeContext();
|
||||
const { recipe, loading, fetchRecipe } = useRecipe(slug);
|
||||
|
||||
const { recipeImage } = useStaticRoutes();
|
||||
|
||||
// @ts-ignore
|
||||
const { $vuetify } = useContext();
|
||||
|
||||
const recipe = getBySlug(slug);
|
||||
|
||||
// ===========================================================================
|
||||
// Layout Helpers
|
||||
|
||||
|
@ -399,7 +397,7 @@ export default defineComponent({
|
|||
async function closeEditor() {
|
||||
state.form = false;
|
||||
state.jsonEditor = false;
|
||||
recipe.value = await fetchRecipe(slug);
|
||||
await fetchRecipe();
|
||||
}
|
||||
|
||||
function toggleJson() {
|
||||
|
|
|
@ -75,10 +75,8 @@
|
|||
import { defineComponent, ref, useRoute, useRouter } from "@nuxtjs/composition-api";
|
||||
import { Food, ParsedIngredient, Parser } from "~/api/class-interfaces/recipes";
|
||||
import RecipeIngredientEditor from "~/components/Domain/Recipe/RecipeIngredientEditor.vue";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useRecipeContext } from "~/composables/use-recipe-context";
|
||||
import { useFoods } from "~/composables/use-recipe-foods";
|
||||
import { useUnits } from "~/composables/use-recipe-units";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useRecipe, useFoods, useUnits } from "~/composables/recipes";
|
||||
import { RecipeIngredientUnit } from "~/types/api-types/recipe";
|
||||
|
||||
interface Error {
|
||||
|
@ -99,11 +97,9 @@ export default defineComponent({
|
|||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const slug = route.value.params.slug;
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const { getBySlug, loading } = useRecipeContext();
|
||||
|
||||
const recipe = getBySlug(slug);
|
||||
const { recipe, loading } = useRecipe(slug);
|
||||
|
||||
const ingredients = ref<any[]>([]);
|
||||
|
||||
|
|
|
@ -313,7 +313,7 @@
|
|||
import { defineComponent, reactive, toRefs, ref, useRouter, useContext } from "@nuxtjs/composition-api";
|
||||
// @ts-ignore No Types for v-jsoneditor
|
||||
import VJsoneditor from "v-jsoneditor";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import RecipeCategoryTagSelector from "~/components/Domain/Recipe/RecipeCategoryTagSelector.vue";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
|
@ -357,7 +357,7 @@ export default defineComponent({
|
|||
},
|
||||
];
|
||||
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const router = useRouter();
|
||||
|
||||
function handleResponse(response: any, edit: Boolean = false) {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
import { defineComponent, onMounted, ref } from "@nuxtjs/composition-api";
|
||||
import { useThrottleFn } from "@vueuse/core";
|
||||
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
|
||||
import { useLazyRecipes } from "~/composables/use-recipes";
|
||||
import { useLazyRecipes } from "~/composables/recipes";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipeCardSection },
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, useAsync, useRoute } from "@nuxtjs/composition-api";
|
||||
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipeCardSection },
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const route = useRoute();
|
||||
const slug = route.value.params.slug;
|
||||
|
||||
|
|
|
@ -28,12 +28,12 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, useAsync } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useAsyncKey } from "~/composables/use-utils";
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const categories = useAsync(async () => {
|
||||
const { data } = await api.categories.getAll();
|
||||
|
|
|
@ -13,13 +13,13 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, useAsync, useRoute } from "@nuxtjs/composition-api";
|
||||
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { Recipe } from "~/types/api-types/admin";
|
||||
|
||||
export default defineComponent({
|
||||
components: { RecipeCardSection },
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const route = useRoute();
|
||||
const slug = route.value.params.slug;
|
||||
|
||||
|
|
|
@ -28,12 +28,12 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, useAsync, computed } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useAsyncKey } from "~/composables/use-utils";
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const tags = useAsync(async () => {
|
||||
const { data } = await api.tags.getAll();
|
||||
|
|
|
@ -101,14 +101,14 @@
|
|||
<script lang="ts">
|
||||
import { computed, defineComponent, reactive, toRefs, ref, useRouter, watch } from "@nuxtjs/composition-api";
|
||||
import { validators } from "@/composables/use-validators";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { useRouterQuery } from "@/composables/use-router";
|
||||
|
||||
export default defineComponent({
|
||||
layout: "basic",
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
const state = reactive({
|
||||
joinGroup: false,
|
||||
loggingIn: false,
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, toRefs, reactive } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { validators } from "@/composables/use-validators";
|
||||
import { useRouteQuery } from "~/composables/use-router";
|
||||
|
@ -92,7 +92,7 @@ export default defineComponent({
|
|||
|
||||
// ===================
|
||||
// API
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
async function requestLink() {
|
||||
state.loading = true;
|
||||
// TODO: Fix Response to send meaningful error
|
||||
|
|
|
@ -70,7 +70,7 @@ import { defineComponent } from "@nuxtjs/composition-api";
|
|||
import RecipeSearchFilterSelector from "~/components/Domain/Recipe/RecipeSearchFilterSelector.vue";
|
||||
import RecipeCategoryTagSelector from "~/components/Domain/Recipe/RecipeCategoryTagSelector.vue";
|
||||
import RecipeCardSection from "~/components/Domain/Recipe/RecipeCardSection.vue";
|
||||
import { useRecipes, allRecipes } from "~/composables/use-recipes";
|
||||
import { useRecipes, allRecipes } from "~/composables/recipes";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
|
|
|
@ -64,12 +64,12 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, onMounted, useContext } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { UserOut } from "~/types/api-types/user";
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const { i18n } = useContext();
|
||||
|
||||
|
|
|
@ -96,8 +96,8 @@
|
|||
import { defineComponent, reactive, ref, useContext } from "@nuxtjs/composition-api";
|
||||
import RecipeDataTable from "~/components/Domain/Recipe/RecipeDataTable.vue";
|
||||
import RecipeCategoryTagSelector from "~/components/Domain/Recipe/RecipeCategoryTagSelector.vue";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useRecipes, allRecipes } from "~/composables/use-recipes";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useRecipes, allRecipes } from "~/composables/recipes";
|
||||
import { Recipe } from "~/types/api-types/recipe";
|
||||
|
||||
const MODES = {
|
||||
|
@ -169,7 +169,7 @@ export default defineComponent({
|
|||
},
|
||||
];
|
||||
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
function exportSelected() {
|
||||
console.log("Export Selected");
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, useContext, ref } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
|
@ -75,7 +75,7 @@ export default defineComponent({
|
|||
return nuxtContext.$auth.user;
|
||||
});
|
||||
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const domNewTokenForm = ref<VForm | null>(null);
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { ref, reactive, defineComponent, computed, useContext, watch } from "@nuxtjs/composition-api";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
|
@ -117,7 +117,7 @@ export default defineComponent({
|
|||
|
||||
const userCopy = ref({ ...user.value });
|
||||
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
|
||||
const domUpdatePassword = ref<VForm | null>(null);
|
||||
const password = reactive({
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
<script lang="ts">
|
||||
import { computed, defineComponent, useContext, ref, toRefs, reactive } from "@nuxtjs/composition-api";
|
||||
import UserProfileLinkCard from "@/components/Domain/User/UserProfileLinkCard.vue";
|
||||
import { useApiSingleton } from "~/composables/use-api";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
|
||||
|
@ -141,7 +141,7 @@ export default defineComponent({
|
|||
|
||||
const generatedLink = ref("");
|
||||
const token = ref("");
|
||||
const api = useApiSingleton();
|
||||
const api = useUserApi();
|
||||
async function getSignupLink() {
|
||||
const { data } = await api.groups.createInvitation({ uses: 1 });
|
||||
if (data) {
|
||||
|
|
|
@ -91,6 +91,7 @@ export interface RecipeIngredient {
|
|||
export interface RecipeIngredientUnit {
|
||||
name?: string;
|
||||
description?: string;
|
||||
fraction?: boolean;
|
||||
}
|
||||
export interface RecipeIngredientFood {
|
||||
name?: string;
|
||||
|
|
Loading…
Reference in a new issue