ui improvements + mealplanner search

This commit is contained in:
hay-kot 2021-02-13 18:47:41 -09:00
commit 4493894162
11 changed files with 93 additions and 42 deletions

View file

@ -150,4 +150,5 @@ export default {
*::-webkit-scrollbar-thumb { *::-webkit-scrollbar-thumb {
background: grey; background: grey;
} }
</style> </style>

View file

@ -8,13 +8,14 @@ const prefix = baseURL + "recipes/";
const recipeURLs = { const recipeURLs = {
allRecipes: baseURL + "recipes", allRecipes: baseURL + "recipes",
allRecipesByCategory: prefix + "category",
create: prefix + "create", create: prefix + "create",
createByURL: prefix + "create-url", createByURL: prefix + "create-url",
recipe: (slug) => prefix + slug, recipe: slug => prefix + slug,
update: (slug) => prefix + slug, update: slug => prefix + slug,
delete: (slug) => prefix + slug, delete: slug => prefix + slug,
recipeImage: (slug) => `${prefix}${slug}/image`, recipeImage: slug => `${prefix}${slug}/image`,
updateImage: (slug) => `${prefix}${slug}/image`, updateImage: slug => `${prefix}${slug}/image`,
}; };
export default { export default {
@ -27,6 +28,14 @@ export default {
return response; return response;
}, },
async getAllByCategory(categories) {
let response = await apiReq.post(
recipeURLs.allRecipesByCategory,
categories
);
return response.data;
},
async create(recipeData) { async create(recipeData) {
let response = await apiReq.post(recipeURLs.create, recipeData); let response = await apiReq.post(recipeURLs.create, recipeData);
return response.data; return response.data;
@ -67,7 +76,7 @@ export default {
keys: recipeKeys, keys: recipeKeys,
num: num, num: num,
}, },
paramsSerializer: (params) => { paramsSerializer: params => {
return qs.stringify(params, { arrayFormat: "repeat" }); return qs.stringify(params, { arrayFormat: "repeat" });
}, },
}); });

View file

@ -96,6 +96,7 @@ export default {
return { return {
isLoading: false, isLoading: false,
meals: [], meals: [],
items: [],
// Dates // Dates
startDate: null, startDate: null,
@ -117,11 +118,13 @@ export default {
} }
}, },
}, },
async mounted() {
let settings = await api.settings.requestAll();
console.log(settings);
this.items = await api.recipes.getAllByCategory(settings.planCategories);
},
computed: { computed: {
items() {
return this.$store.getters.getRecentRecipes;
},
actualStartDate() { actualStartDate() {
return Date.parse(this.startDate); return Date.parse(this.startDate);
}, },

View file

@ -6,7 +6,19 @@
:to="route ? `/recipe/${slug}` : ''" :to="route ? `/recipe/${slug}` : ''"
@click="$emit('click')" @click="$emit('click')"
> >
<v-img height="200" :src="getImage(image)"></v-img> <v-img height="200" :src="getImage(image)">
<v-expand-transition v-if="description">
<div
v-if="hover"
class="d-flex transition-fast-in-fast-out secondary v-card--reveal "
style="height: 100%;"
>
<v-card-text class="v-card--text-show white--text">
{{ description }}
</v-card-text>
</div>
</v-expand-transition>
</v-img>
<v-card-title class="my-n3 mb-n6">{{ name | truncate(30) }}</v-card-title> <v-card-title class="my-n3 mb-n6">{{ name | truncate(30) }}</v-card-title>
<v-card-actions class=""> <v-card-actions class="">
@ -23,16 +35,7 @@
></v-rating> ></v-rating>
</v-col> </v-col>
<v-col></v-col> <v-col></v-col>
<v-col align="end"> <v-col align="end"> </v-col>
<v-tooltip top color="secondary" max-width="400" open-delay="50">
<template v-slot:activator="{ on, attrs }">
<v-btn color="secondary" v-on="on" v-bind="attrs" text>{{
$t("recipe.description")
}}</v-btn>
</template>
<span>{{ description }}</span>
</v-tooltip>
</v-col>
</v-row> </v-row>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
@ -61,4 +64,15 @@ export default {
</script> </script>
<style> <style>
.v-card--reveal {
align-items: center;
bottom: 0;
justify-content: center;
opacity: 0.8;
position: absolute;
width: 100%;
}
.v-card--text-show {
opacity: 1 !important;
}
</style> </style>

View file

@ -57,6 +57,7 @@ export default {
return { return {
searchSlug: "", searchSlug: "",
search: " ", search: " ",
data: [],
result: [], result: [],
autoResults: [], autoResults: [],
isDark: false, isDark: false,
@ -67,27 +68,31 @@ export default {
distance: 100, distance: 100,
maxPatternLength: 32, maxPatternLength: 32,
minMatchCharLength: 1, minMatchCharLength: 1,
keys: ["name", "slug"], keys: ["name", "slug", "description"],
}, },
}; };
}, },
mounted() { mounted() {
this.isDark = this.$store.getters.getIsDark; this.isDark = this.$store.getters.getIsDark;
this.data = this.$store.getters.getRecentRecipes;
}, },
computed: { computed: {
data() {
return this.$store.getters.getRecentRecipes;
},
fuse() { fuse() {
return new Fuse(this.data, this.options); return new Fuse(this.data, this.options);
}, },
}, },
watch: { watch: {
search() { search() {
if (this.search.trim() === "") this.result = this.list; try {
else this.result = this.fuse.search(this.search.trim()); this.result = this.fuse.search(this.search.trim());
} catch {
this.result = this.data
.map(x => ({ item: x }))
.sort((a, b) => (a.name > b.name ? 1 : -1));
}
console.log(this.result);
this.$emit("results", this.result); this.$emit("results", this.result);
if (this.showResults === true) { if (this.showResults === true) {
this.autoResults = this.result; this.autoResults = this.result;
} }

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="text-center"> <div class="text-center">
<v-dialog v-model="dialog" min-height="700" max-width="1000"> <v-dialog v-model="dialog" height="100%" max-width="1200">
<v-card min-height="725" height="100%"> <v-card min-height="725" height="100%">
<v-card-text> <v-card-text>
<v-card-title></v-card-title> <v-card-title></v-card-title>
@ -22,7 +22,7 @@
:md="6" :md="6"
:lg="4" :lg="4"
:xl="3" :xl="3"
v-for="item in searchResults.slice(0, 10)" v-for="item in searchResults.slice(0, 24)"
:key="item.item.name" :key="item.item.name"
> >
<RecipeCard <RecipeCard
@ -58,6 +58,7 @@ export default {
}, },
methods: { methods: {
updateResults(results) { updateResults(results) {
console.log(results);
this.searchResults = results; this.searchResults = results;
}, },
emitSelect(name, slug) { emitSelect(name, slug) {

View file

@ -15,7 +15,7 @@ const mutations = {
state.showLimit = payload; state.showLimit = payload;
}, },
setCategories(state, payload) { setCategories(state, payload) {
state.categories = payload; state.categories = payload.sort((a, b) => (a.name > b.name ? 1 : -1));
}, },
setHomeCategories(state, payload) { setHomeCategories(state, payload) {
state.homeCategories = payload; state.homeCategories = payload;

View file

@ -47,7 +47,6 @@ const store = new Vuex.Store({
}, },
setMealPlanCategories(state, payload) { setMealPlanCategories(state, payload) {
console.log(payload);
state.mealPlanCategories = payload; state.mealPlanCategories = payload;
}, },
}, },

View file

@ -100,11 +100,17 @@ class BaseDocument:
match_key = self.primary_key match_key = self.primary_key
result = ( result = (
session.query(self.sql_model).filter_by(**{match_key: match_value}).one() session.query(self.sql_model)
.filter_by(**{match_key: match_value})
.limit(limit)
.all()
) )
db_entry = result.dict() db_entries = [x.dict() for x in result]
return db_entry if limit == 1:
return db_entries[0]
return db_entries
def create(self, session: Session, document: dict) -> dict: def create(self, session: Session, document: dict) -> dict:
"""Creates a new database entry for the given SQL Alchemy Model. """Creates a new database entry for the given SQL Alchemy Model.

View file

@ -4,6 +4,7 @@ from db.database import db
from db.db_setup import generate_session from db.db_setup import generate_session
from fastapi import APIRouter, Depends, Query from fastapi import APIRouter, Depends, Query
from models.recipe_models import AllRecipeRequest from models.recipe_models import AllRecipeRequest
from slugify import slugify
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
router = APIRouter(tags=["Query All Recipes"]) router = APIRouter(tags=["Query All Recipes"])
@ -71,13 +72,23 @@ def get_all_recipes_post(
return db.recipes.get_all_limit_columns(session, body.properties, body.limit) return db.recipes.get_all_limit_columns(session, body.properties, body.limit)
@router.post("/api/category") @router.post("/api/recipes/category")
async def filter_by_category( def filter_by_category(categories: list, session: Session = Depends(generate_session)):
categories: list, session: Session = Depends(generate_session)
):
""" pass a list of categories and get a list of recipes associated with those categories """ """ pass a list of categories and get a list of recipes associated with those categories """
#! This should be refactored into a single database call, but I couldn't figure it out #! This should be refactored into a single database call, but I couldn't figure it out
in_category = [db.categories.get(session, cat) for cat in categories] in_category = [
db.categories.get(session, slugify(cat), limit=1) for cat in categories
]
in_category = [cat.get("recipes") for cat in in_category] in_category = [cat.get("recipes") for cat in in_category]
in_category = [item for sublist in in_category for item in sublist] in_category = [item for sublist in in_category for item in sublist]
return in_category return in_category
@router.post("/api/recipes/tag")
async def filter_by_tags(tags: list, session: Session = Depends(generate_session)):
""" pass a list of tags and get a list of recipes associated with those tags"""
#! This should be refactored into a single database call, but I couldn't figure it out
in_tags = [db.tags.get(session, slugify(tag), limit=1) for tag in tags]
in_tags = [tag.get("recipes") for tag in in_tags]
in_tags = [item for sublist in in_tags for item in sublist]
return in_tags

View file

@ -69,8 +69,10 @@ def delete_recipe(recipe_slug: str, db: Session = Depends(generate_session)):
async def get_recipe_img(recipe_slug: str): async def get_recipe_img(recipe_slug: str):
""" Takes in a recipe slug, returns the static image """ """ Takes in a recipe slug, returns the static image """
recipe_image = read_image(recipe_slug) recipe_image = read_image(recipe_slug)
if recipe_image:
return FileResponse(recipe_image) return FileResponse(recipe_image)
else:
return
@router.put("/{recipe_slug}/image") @router.put("/{recipe_slug}/image")