enrecipes/app/components/MealPlanner.vue
2020-12-29 16:05:19 +05:30

356 lines
13 KiB
Vue

<template>
<Page @loaded="onPageLoad">
<ActionBar flat="true">
<GridLayout rows="*" columns="auto, *, auto">
<MDButton class="bx left" variant="text" :text="icon.menu" automationText="Back" @tap="showDrawer" col="0" />
<Label class="title orkm" :text="'Meal Planner' | L" col="1" />
<MDButton class="bx left" variant="text" :text="icon.today" automationText="today" @tap="goToToday" col="2" />
</GridLayout>
</ActionBar>
<GridLayout rows="280, *">
<RadCalendar :androidElevation="viewIsScrolled ? 4 : 0" class="orkm" row="0" ref="calendar" @loaded="onCalendarLoad" @dateSelected="onDateSelected" :viewMode="viewMode" :transitionMode="transitionMode" :selectionMode="selectionMode"
:eventsViewMode="eventsViewMode" :eventSource="getMealPlans"></RadCalendar>
<ScrollView row="1" width="100%" height="100%" @scroll="onScroll">
<StackLayout class="dayPlan">
<StackLayout v-for="(mealType, index) in mealTimes" :key="'mealType' + index" class="plansContainer" :class="mealType">
<GridLayout columns="*, auto" class="header">
<Label col="0" class="periodLabel orkm" :text="mealType | L" />
<MDButton col="1" variant="text" class="bx" :text="icon.plus" @tap="addRecipe(mealType)" />
</GridLayout>
<GridLayout class="recipes" :paddingTop="index == 0?8:0" columns="*" v-for="(recipeID, index) in getRecipes[mealType]" :key="mealType + index">
<MDRipple @tap="viewRecipe(recipeID)" @longPress="removeRecipe(mealType, recipeID)" />
<Label verticalAlignment="center" class="recipeTitle" col="0" :text="getRecipeTitle(recipeID)" textWrap="true" />
</GridLayout>
</StackLayout>
</StackLayout>
</ScrollView>
</GridLayout>
</Page>
</template>
<script>
import {
ApplicationSettings,
Color,
Page,
Observable,
Device
}
from "@nativescript/core"
import {
CalendarViewMode,
CalendarTransitionMode,
CalendarSelectionMode,
CalendarMonthViewStyle,
CalendarSelectionShape,
DayCellStyle,
CalendarFontStyle,
CalendarCellAlignment,
CellStyle,
CalendarEventsViewMode,
CalendarEvent
}
from "nativescript-ui-calendar"
import {
mapState,
mapActions
}
from "vuex"
import ViewRecipe from "./ViewRecipe.vue"
import ActionDialogWithSearch from "./modal/ActionDialogWithSearch.vue"
import ConfirmDialog from "./modal/ConfirmDialog.vue"
import * as utils from "~/shared/utils"
export default {
data() {
return {
viewIsScrolled: false,
appTheme: "Light",
mealTimes: [ "breakfast", "lunch", "dinner", "snacks" ],
eventList: [],
selectedDayMealPlans: [],
viewMode: CalendarViewMode.Month,
transitionMode: CalendarTransitionMode.Slide,
selectionMode: CalendarSelectionMode.Single,
eventsViewMode: CalendarEventsViewMode.None,
color: {
white: new Color( "#ffffff" ),
gray1: new Color( "#f1f3f5" ),
gray2: new Color( "#e9ecef" ),
gray3: new Color( "#dee2e6" ),
gray4: new Color( "#ced4da" ),
gray5: new Color( "#adb5bd" ),
gray6: new Color( "#868e96" ),
gray7: new Color( "#495057" ),
gray8: new Color( "#343a40" ),
gray9: new Color( "#212529" ),
black: new Color( "#111111" ),
orange: new Color( "#ff5200" ),
breakfast: "#ff922b",
lunch: "#94d82d",
dinner: "#339af0",
snacks: "#845ef7",
},
appFontRegular: "Orkney-Regular",
appFontMedium: "Orkney-Medium",
selectedDate: null,
}
},
computed: {
...mapState( [ "icon", "recipes", "mealPlans" ] ),
isLightMode() {
return this.appTheme === "Light"
},
monthViewStyle() {
const monthViewStyle = new CalendarMonthViewStyle()
monthViewStyle.backgroundColor = this.isLightMode ? this.color.gray1 : this.color.gray9
monthViewStyle.showTitle = true
monthViewStyle.showWeekNumbers = false
monthViewStyle.showDayNames = true
const titleCellStyle = new DayCellStyle()
titleCellStyle.cellBackgroundColor = this.isLightMode ? this.color.gray2 : this.color.black
titleCellStyle.cellBorderWidth = 1
titleCellStyle.cellBorderColor = this.isLightMode ? this.color.gray2 : this.color.black
titleCellStyle.cellTextSize = 16
titleCellStyle.cellTextColor = this.isLightMode ? this.color.gray9 : this.color.gray1
titleCellStyle.cellTextFontName = this.appFontMedium
monthViewStyle.titleCellStyle = titleCellStyle
const dayNameCellStyle = new CellStyle()
dayNameCellStyle.cellBackgroundColor = this.isLightMode ? this.color.gray2 : this.color.black
dayNameCellStyle.cellTextColor = this.isLightMode ? this.color.gray9 : this.color.gray1
dayNameCellStyle.cellBorderWidth = 1
dayNameCellStyle.cellBorderColor = this.isLightMode ? this.color.gray2 : this.color.black
dayNameCellStyle.cellTextSize = 10
dayNameCellStyle.cellAlignment = CalendarCellAlignment.Center
dayNameCellStyle.cellTextFontName = this.appFontMedium
monthViewStyle.dayNameCellStyle = dayNameCellStyle
const dayCellStyle = new DayCellStyle()
dayCellStyle.showEventsText = false
dayCellStyle.eventTextColor = this.color.orange
dayCellStyle.eventFontName = this.appFontRegular
dayCellStyle.eventFontStyle = CalendarFontStyle.Bold
dayCellStyle.eventTextSize = 8
dayCellStyle.cellTextSize = 16
dayCellStyle.cellTextColor = this.isLightMode ? this.color.gray9 : this.color.gray1
dayCellStyle.cellAlignment = CalendarCellAlignment.Bottom
dayCellStyle.cellBackgroundColor = this.isLightMode ? this.color.gray1 : this.color.gray9
dayCellStyle.cellTextFontName = this.appFontRegular
dayCellStyle.cellBorderWidth = 1
dayCellStyle.cellBorderColor = this.isLightMode ? this.color.gray2 : this.color.black
monthViewStyle.dayCellStyle = dayCellStyle
const todayCellStyle = new DayCellStyle()
todayCellStyle.cellBackgroundColor = this.isLightMode ? this.color.gray1 : this.color.gray9
todayCellStyle.cellTextColor = this.color.orange
todayCellStyle.cellBorderWidth = 1
todayCellStyle.cellTextFontName = this.appFontMedium
todayCellStyle.cellTextFontStyle = CalendarFontStyle.Bold
todayCellStyle.cellTextSize = 16
todayCellStyle.cellAlignment = CalendarCellAlignment.Bottom
todayCellStyle.cellBorderColor = this.isLightMode ? this.color.gray2 : this.color.black
monthViewStyle.todayCellStyle = todayCellStyle
const selectedCellStyle = new DayCellStyle()
selectedCellStyle.eventTextSize = 1
selectedCellStyle.cellAlignment = CalendarCellAlignment.Bottom
selectedCellStyle.cellBackgroundColor = this.isLightMode ? this.color.white : this.color.gray8
selectedCellStyle.cellBorderWidth = 1
selectedCellStyle.cellBorderColor = this.color.orange
selectedCellStyle.cellTextColor = this.isLightMode ? this.color.gray9 : this.color.gray1
selectedCellStyle.cellTextFontName = this.appFontMedium
selectedCellStyle.cellTextFontStyle = CalendarFontStyle.Bold
selectedCellStyle.cellTextSize = 16
monthViewStyle.selectedDayCellStyle = selectedCellStyle
return monthViewStyle
},
getRecipes() {
if ( this.selectedDayMealPlans.length ) {
return this.selectedDayMealPlans.reduce( ( acc, e ) => {
switch ( e.startDate.getHours() ) {
case 0: //breakfast
acc[ "breakfast" ] = [ ...( acc[ "breakfast" ] || [] ), e.title ]
break
case 5: //lunch
acc[ "lunch" ] = [ ...( acc[ "lunch" ] || [] ), e.title ]
break
case 10: //dinner
acc[ "dinner" ] = [ ...( acc[ "dinner" ] || [] ), e.title ]
break
case 15: //snacks
acc[ "snacks" ] = [ ...( acc[ "snacks" ] || [] ), e.title ]
break
default:
break
}
return acc
}, {} )
} else return 0
},
getMealPlans() {
const getDate = ( date ) => {
let d = new Date( date )
let result = new Date( d.getFullYear(), d.getMonth(), d.getDate(), d.getHours() )
return result
}
let events = []
this.mealPlans.forEach( ( plan ) => {
let e = new CalendarEvent( plan.title, getDate( plan.startDate ), getDate( plan.endDate ), false, new Color( plan.eventColor ) )
events = [ ...events, e ]
} )
return events
},
},
methods: {
...mapActions( [ "setCurrentComponentAction", "initializeMealPlans", "addMealPlanAction", "deleteMealPlanAction", ] ),
onPageLoad( args ) {
const page = args.object;
page.bindingContext = new Observable();
this.setCurrentComponentAction( "MealPlanner" )
},
onCalendarLoad( args ) {
args.object.locale = `${Device.language}-${Device.language.toUpperCase()}`
args.object.monthViewStyle = this.monthViewStyle
args.object.android.getGestureManager().setDoubleTapToChangeDisplayMode( false )
args.object.android.getGestureManager().setPinchCloseToChangeDisplayMode( false )
if ( args.object.selectedDate == null ) args.object.selectedDate = new Date()
if ( args.object.nativeView.getEventAdapter() ) {
args.object.nativeView.getEventAdapter().getRenderer().setEventRenderMode( com.telerik.widget.calendar.events.EventRenderMode.Shape )
}
},
// HELPERS
showDrawer() {
utils.showDrawer()
},
onScroll( args ) {
this.viewIsScrolled = args.scrollY ? true : false
},
getDate( index ) {
let date = new Date()
date.setDate( date.getDate() + index )
return date.getTime()
},
getDateString( days ) {
let date = new Date()
date.setDate( date.getDate() + days )
return date.toDateString().slice( 0, -5 )
},
getRecipeTitle( id ) {
let recipe = this.recipes.filter( ( e ) => e.id === id )[ 0 ]
return recipe ? recipe.title : `[ ${this.$options.filters.L('Recipe not found')} ]`
},
// NAVIGATION HANDLERS
viewRecipe( recipeID ) {
let recipe = this.recipes.filter( ( e ) => e.id === recipeID )[ 0 ]
if ( recipe ) {
this.$navigateTo( ViewRecipe, {
props: {
filterTrylater: true,
recipeID,
},
backstackVisible: false,
} )
}
},
// DATA HANDLERS
addRecipe( mealType ) {
let filteredRecipes = this.recipes.filter( ( e ) => this.getRecipes[ mealType ] ? !this.getRecipes[ mealType ].includes( e.id ) : true )
this.$showModal( ActionDialogWithSearch, {
props: {
title: "Select a recipe",
recipes: filteredRecipes,
},
} ).then( ( recipeID ) => {
recipeID && this.newEvent( recipeID, mealType )
} )
},
removeRecipeConfirm( mealType ) {
return this.$showModal( ConfirmDialog, {
props: {
title: `Remove recipe from ${mealType}?`,
cancelButtonText: "CANCEL",
okButtonText: "REMOVE",
},
} )
},
removeRecipe( mealType, recipeID ) {
let startHour = {
breakfast: 0,
lunch: 5,
dinner: 10,
snacks: 15,
}
this.removeRecipeConfirm( mealType ).then( ( res ) => {
if ( res ) {
let actualMealPlan = this.selectedDayMealPlans.filter(
( e ) => e.startDate.getHours() === startHour[ mealType ] && e.title === recipeID )[ 0 ]
let mealPlan = {
title: actualMealPlan.title,
startDate: actualMealPlan.startDate,
}
this.deleteMealPlanAction( mealPlan )
this.updateSelectedDatePlans()
}
} )
},
// CALENDAR
updateSelectedDatePlans() {
let date = new Date( this.selectedDate )
setTimeout( () => {
this.selectedDayMealPlans = this.$refs.calendar.nativeView.getEventsForDate( date )
}, 100 )
},
onDateSelected( args ) {
this.selectedDate = args.date
this.selectedDayMealPlans = args.object.getEventsForDate( args.date )
},
newEvent( recipeID, mealType ) {
let date = new Date( this.selectedDate )
const selectedDate = () => {
return {
y: date.getFullYear(),
m: date.getMonth(),
d: date.getDate(),
}
}
let {
y,
m,
d
} = selectedDate()
let mealTime = {
breakfast: {
start: new Date( y, m, d, 0 ),
end: new Date( y, m, d, 4 ),
},
lunch: {
start: new Date( y, m, d, 5 ),
end: new Date( y, m, d, 9 ),
},
dinner: {
start: new Date( y, m, d, 10 ),
end: new Date( y, m, d, 14 ),
},
snacks: {
start: new Date( y, m, d, 15 ),
end: new Date( y, m, d, 19 ),
},
}
let event = new CalendarEvent( recipeID, mealTime[ mealType ].start, mealTime[ mealType ].end, false, new Color( this.color[ mealType ] ) )
this.addMealPlanAction( {
event,
eventColor: this.color[ mealType ]
} )
this.updateSelectedDatePlans()
},
goToToday() {
const date = new Date()
this.$refs.calendar.goToDate( date )
this.$refs.calendar.nativeView.selectedDate = date
},
},
created() {
this.appTheme = ApplicationSettings.getString( "appTheme", "Light" )
let d = new Date()
d.setHours( 0, 0, 0 )
this.selectedDate = d
},
}
</script>