Bug/general fixes (#450)

* Fix asset link

* remove unused var

* fix no meal-plan returned

* cleanup redundant code

* Fix dates off in UI

* quick set dark/light mode

* user image fixes

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden 2021-05-31 18:44:20 -08:00 committed by GitHub
parent 785ab184af
commit 22d9309112
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 218 additions and 16352 deletions

16343
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -160,7 +160,7 @@ export const recipeAPI = {
},
recipeAssetPath(recipeSlug, assetName) {
return `api/media/recipes/${recipeSlug}/assets/${assetName}`;
return `/api/media/recipes/${recipeSlug}/assets/${assetName}`;
},
/** Create comment in the Database

View File

@ -113,6 +113,11 @@ export const userAPI = {
const response = await apiReq.delete(API_ROUTES.usersIdFavoritesSlug(id, slug));
return response.data;
},
userProfileImage(id) {
if (!id || id === undefined) return;
return `/api/users/${id}/image`;
},
};
const deleteErrorText = response => {

View File

@ -67,12 +67,13 @@
</v-card-text>
<v-row align="center" justify="end">
<v-card-actions class="mr-5">
<v-btn color="success" @click="random" v-if="planDays.length > 0" text>
<TheButton edit @click="random" v-if="planDays.length > 0" text>
<template v-slot:icon>
mdi-dice-multiple
</template>
{{ $t("general.random") }}
</v-btn>
<v-btn color="success" @click="save" text :disabled="planDays.length == 0">
{{ $t("general.save") }}
</v-btn>
</TheButton>
<TheButton create @click="save" :disabled="planDays.length == 0" />
</v-card-actions>
</v-row>
</v-card>
@ -105,6 +106,9 @@ export default {
},
watch: {
startDate(val) {
console.log(val);
},
dateDif() {
this.planDays = [];
for (let i = 0; i < this.dateDif; i++) {
@ -132,22 +136,19 @@ export default {
return this.$store.getters.getCurrentGroup;
},
actualStartDate() {
return Date.parse(this.startDate);
if (!this.startDate) return null;
return Date.parse(this.startDate.replaceAll("-", "/"));
},
actualEndDate() {
return Date.parse(this.endDate);
if (!this.endDate) return null;
return Date.parse(this.endDate.replaceAll("-", "/"));
},
dateDif() {
let startDate = new Date(this.startDate);
let endDate = new Date(this.endDate);
console.log(startDate, endDate);
let dateDif = (endDate - startDate) / (1000 * 3600 * 24) + 1;
if (!this.actualEndDate || !this.actualStartDate) return null;
let dateDif = (this.actualEndDate - this.actualStartDate) / (1000 * 3600 * 24) + 1;
if (dateDif < 1) {
return null;
}
return dateDif;
},
startComputedDateFormatted() {
@ -179,22 +180,17 @@ export default {
},
random() {
this.usedRecipes = [1];
this.planDays.forEach((element, index) => {
this.planDays.forEach((_, index) => {
let recipe = this.getRandom(this.filteredRecipes);
this.planDays[index]["meals"][0]["slug"] = recipe.slug;
this.planDays[index]["meals"][0]["name"] = recipe.name;
this.usedRecipes.push(recipe);
});
},
processTime(index) {
let dateText = new Date(this.actualStartDate.valueOf() + 1000 * 3600 * 24 * index);
return dateText;
},
getDate(index) {
const dateObj = this.processTime(index);
const dateObj = new Date(this.actualStartDate.valueOf() + 1000 * 3600 * 24 * index);
return utils.getDateAsPythonDate(dateObj);
},
async save() {
const mealBody = {
group: this.groupSettings.name,
@ -209,7 +205,6 @@ export default {
this.endDate = null;
}
},
formatDate(date) {
if (!date) return null;
@ -227,12 +222,9 @@ export default {
const nextEndDate = new Date(nextMonday);
nextEndDate.setDate(nextEndDate.getDate() + 4);
this.startDate = nextMonday.toISOString().substr(0, 10);
this.endDate = nextEndDate.toISOString().substr(0, 10);
this.startDate = utils.getDateAsPythonDate(nextMonday);
this.endDate = utils.getDateAsPythonDate(nextEndDate);
},
},
};
</script>
<style></style>

View File

@ -91,7 +91,7 @@ export default {
this.hideImage == false;
},
getProfileImage(id) {
return `api/users/${id}/image`;
return api.users.userProfileImage(id);
},
editComment(id) {
this.$set(this.editKeys, id, true);

View File

@ -21,9 +21,7 @@
<v-btn color="error" icon @click="deleteAsset(i)" top>
<v-icon>{{ $globals.icons.delete }}</v-icon>
</v-btn>
<v-btn color="primary" icon @click="copyLink(item.name, item.fileName)" top>
<v-icon>mdi-content-copy</v-icon>
</v-btn>
<TheCopyButton :copy-text="copyLink(item.fileName)" />
</div>
</v-list-item-action>
</v-list-item>
@ -60,6 +58,7 @@
</template>
<script>
import TheCopyButton from "@/components/UI/Buttons/TheCopyButton";
import TheUploadBtn from "@/components/UI/Buttons/TheUploadBtn";
import BaseDialog from "@/components/UI/Dialogs/BaseDialog";
import { api } from "@/api";
@ -67,6 +66,7 @@ export default {
components: {
BaseDialog,
TheUploadBtn,
TheCopyButton,
},
props: {
slug: String,
@ -130,13 +130,9 @@ export default {
deleteAsset(index) {
this.value.splice(index, 1);
},
copyLink(name, fileName) {
copyLink(fileName) {
const assetLink = api.recipes.recipeAssetPath(this.slug, fileName);
const copyText = `![${name}](${assetLink})`;
navigator.clipboard.writeText(copyText).then(
() => console.log("Copied", copyText),
() => console.log("Copied Failed", copyText)
);
return `<img src="${this.baseURL}${assetLink}" height="100%" width="100%"> </img>`;
},
},
};

View File

@ -4,6 +4,7 @@
:small="small"
:x-small="xSmall"
:loading="loading"
:disabled="disabled"
@click="$emit('click')"
:outlined="btnStyle.outlined"
:text="btnStyle.text"
@ -49,6 +50,10 @@ export default {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
// Styles
small: {
type: Boolean,

View File

@ -18,6 +18,9 @@
</div>
<v-spacer></v-spacer>
<v-btn icon class="mr-1" small @click="isDark = !isDark">
<v-icon v-text="isDark ? 'mdi-weather-night' : 'mdi-weather-sunny'"> </v-icon>
</v-btn>
<div v-if="!isMobile" style="width: 350px;">
<SearchBar :show-results="true" @selected="navigateFromSearch" :max-width="isMobile ? '100%' : '450px'" />
</div>
@ -67,12 +70,25 @@ export default {
isMobile() {
return this.$vuetify.breakpoint.name === "xs";
},
isDark: {
get() {
return this.$store.getters.getIsDark;
},
set() {
let setVal = "dark";
if (this.isDark) {
setVal = "light";
}
this.$store.commit("setDarkMode", setVal);
},
},
},
methods: {
navigateFromSearch(slug) {
this.$router.push(`/recipe/${slug}`);
},
openSidebar() {
console.log(this.isDarkMode);
this.$refs.theSidebar.toggleSidebar();
},
},

View File

@ -2,19 +2,7 @@
<div class="d-print-none no-print">
<v-navigation-drawer v-model="showSidebar" width="180px" clipped app>
<template v-slot:prepend>
<v-list-item two-line v-if="isLoggedIn" to="/admin/profile">
<v-list-item-avatar color="accent" class="white--text">
<img :src="userProfileImage" v-if="!hideImage" @error="hideImage = true" />
<div v-else>
{{ initials }}
</div>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title> {{ user.fullName }}</v-list-item-title>
<v-list-item-subtitle> {{ user.admin ? $t("user.admin") : $t("user.user") }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<UserAvatar v-if="isLoggedIn" :user="user" />
<v-list-item dense v-if="isLoggedIn" :to="`/user/${user.id}/favorites`">
<v-list-item-icon>
@ -46,7 +34,7 @@
mdi-heart
</v-icon>
</v-list-item-icon>
<v-list-item-title> {{$t('about.support')}} </v-list-item-title>
<v-list-item-title> {{ $t("about.support") }} </v-list-item-title>
</v-list-item>
<v-list-item to="/admin/about">
<v-list-item-icon class="mr-3 pt-1">
@ -78,10 +66,14 @@
</template>
<script>
import UserAvatar from "@/components/User/UserAvatar";
import { initials } from "@/mixins/initials";
import { user } from "@/mixins/user";
import axios from "axios";
export default {
components: {
UserAvatar,
},
mixins: [initials, user],
data() {
return {

View File

@ -0,0 +1,61 @@
<template>
<v-list-item two-line to="/admin/profile">
<v-list-item-avatar color="accent" class="white--text">
<v-img :src="profileImage" v-if="!noImage" />
<div v-else>
{{ initials }}
</div>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title> {{ user.fullName }}</v-list-item-title>
<v-list-item-subtitle> {{ user.admin ? $t("user.admin") : $t("user.user") }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</template>
<script>
import { initials } from "@/mixins/initials";
import axios from "axios";
import { api } from "@/api";
export default {
mixins: [initials],
props: {
user: {
type: Object,
},
},
data() {
return {
noImage: false,
profileImage: "",
};
},
watch: {
async user() {
this.setImage();
},
},
methods: {
async setImage() {
const userImageURL = api.users.userProfileImage(this.user.id);
if (await this.imageExists(userImageURL)) {
this.noImage = false;
this.profileImage = userImageURL;
} else {
this.noImage = true;
}
},
async imageExists(url) {
const response = await axios.get(url).catch(() => {
this.noImage = true;
return { status: 404 };
});
return response.status !== 404;
},
},
};
</script>
<style lang="scss" scoped>
</style>

View File

@ -73,8 +73,7 @@
</v-virtual-scroll>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<TheButton class="mt-1 mb-n1" create @click="createTheme" />
<TheButton class="ml-auto mt-1 mb-n1" create @click="createTheme" />
</v-card-actions>
</template>
</StatCard>

View File

@ -134,7 +134,7 @@ export default {
computed: {
userProfileImage() {
return `api/users/${this.user.id}/image`;
return api.users.userProfileImage(this.user.id);
},
},

View File

@ -17,7 +17,7 @@ function inDarkMode(payload) {
const state = {
activeTheme: {},
darkMode: "light",
darkMode: "light", // light, dark, system
isDark: false,
isLoggedIn: false,
token: "",

View File

@ -6,10 +6,10 @@ import { store } from "@/store";
export const utils = {
recipe: recipe,
generateUniqueKey(item, index) {
const uniqueKey = `${item}-${index}`;
return uniqueKey;
return `${item}-${index}`;
},
getDateAsPythonDate(dateObject) {
if (!dateObject) return null;
const month = dateObject.getMonth() + 1;
const day = dateObject.getDate();
const year = dateObject.getFullYear();

View File

@ -23,6 +23,28 @@ def get_all_meals(
return db.groups.get_meals(session, current_user.group)
@router.get("/this-week", response_model=MealPlanOut)
def get_this_week(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)):
""" Returns the meal plan data for this week """
plans = db.groups.get_meals(session, current_user.group)
print(plans)
if plans:
return plans[0]
@router.get("/today", tags=["Meal Plan"])
def get_today(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)):
"""
Returns the recipe slug for the meal scheduled for today.
If no meal is scheduled nothing is returned
"""
group_in_db: GroupInDB = db.groups.get(session, current_user.group, "name")
recipe = get_todays_meal(session, group_in_db)
if recipe:
return recipe
@router.get("/{id}", response_model=MealPlanOut)
def get_meal_plan(
id,
@ -86,27 +108,6 @@ def delete_meal_plan(
raise HTTPException(status.HTTP_400_BAD_REQUEST)
@router.get("/this-week", response_model=MealPlanOut)
def get_this_week(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)):
""" Returns the meal plan data for this week """
plans = db.groups.get_meals(session, current_user.group)
if plans:
return plans[0]
@router.get("/today", tags=["Meal Plan"])
def get_today(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)):
"""
Returns the recipe slug for the meal scheduled for today.
If no meal is scheduled nothing is returned
"""
group_in_db: GroupInDB = db.groups.get(session, current_user.group, "name")
recipe = get_todays_meal(session, group_in_db)
if recipe:
return recipe
@router.get("/today/image", tags=["Meal Plan"])
def get_todays_image(session: Session = Depends(generate_session), group_name: str = "Home"):
"""

View File

@ -91,7 +91,7 @@ async def get_user_image(id: str):
for recipe_image in user_dir.glob("profile_image.*"):
return FileResponse(recipe_image)
else:
return False
raise HTTPException(status.HTTP_404_NOT_FOUND)
@router.post("/{id}/image", dependencies=[Depends(get_current_user)])