Selaa lähdekoodia

Stop using week as key for fetching/saving planners: Use date range instead

Tatiana Inama 7 vuotta sitten
vanhempi
commit
7f709ebb75

+ 15 - 53
ktchn/src/planner/controller.ts

@@ -1,21 +1,13 @@
-import { WriteOpResult } from 'mongodb';
 import { IMongoService, IDBDocument } from '../mongo';
 import { ChainPController } from '../promise-all-middleware';
 import PlanDB, { WeeklyPlanner, CompletePlanDB, Weekday, Plan, CompactWeeklyPlanner } from './model';
 import moment, { Moment } from 'moment';
 import { ObjectId } from 'bson';
-import { Request, NextFunction, Response } from 'express';
 
 type Controller<U, T> = (db: IMongoService) => ChainPController<U, T>;
 
 export const getWeekDay = (day: Moment): Weekday => day.format('dddd').toLowerCase() as Weekday;
 
-const mkWeekQuery = (week: string) => ({
-  week: parseInt(week) || moment().isoWeek()
-});
-
-const validatePlan = (mbPlan: any) => mbPlan.date && mbPlan.week && mbPlan.recipe && mbPlan.meal;
-
 const validPlan = (mbPlan: any): Promise<Plan> => {
   if (mbPlan.date && mbPlan.week && mbPlan.recipe && mbPlan.meal) {
     return Promise.resolve({
@@ -28,51 +20,21 @@ const validPlan = (mbPlan: any): Promise<Plan> => {
   }
 }
 
-const getWeekPlanner: Controller<void, PlanDB[]> =
-  db => req => () => db.find<PlanDB>(mkWeekQuery(req.params.week));
-
-const completePlanner: Controller<PlanDB[], WeeklyPlanner> = db => req => prevResult => {
-  const week = mkWeekQuery(req.params.week).week;
-  return db.aggregate<CompletePlanDB>([
-    {
-      '$match': {
-        'week': week
-      }
-    },
-    {
-      '$lookup': {
-        'from': 'recipes', 
-        'localField': 'recipe', 
-        'foreignField': '_id', 
-        'as': 'recipe'
-      }
-    }, {
-      '$unwind': {
-        'path': '$recipe'
-      }
-    }
-  ]).then(plans => plans.reduce((planner, plan) => {
-    const date = moment(plan.date);
-    return {
-      ...planner,
-      [getWeekDay(date)]: {
-        ...planner[getWeekDay(date)],
-        date: date,
-        [plan.meal]: plan.recipe
-      }
-    };
-  }, { week } as WeeklyPlanner))
+const validateRange: Controller<void, {from: Date, to: Date}> = () => req => () => {
+  const from = moment(req.params.from),
+        to = moment(req.params.to);
+  return from.isValid() && to.isValid() && to.diff(from, 'days') === 6 ?
+    Promise.resolve({ from: from.toDate(), to: to.toDate()}) :
+    Promise.reject('Invalid date range');
 }
 
-const compactPlanner: Controller<null, CompactWeeklyPlanner> = db => req => prevResult => {
-  const week = mkWeekQuery(req.params.week).week;
+const getPlannerByRange: Controller<{from: Date, to: Date}, WeeklyPlanner> = db => () => ({ from, to }) => {
   return db.aggregate<CompletePlanDB>([
     {
       '$match': {
-        'week': week
+        'date': {'$gte': from, '$lte': to}
       }
-    },
-    {
+    }, {
       '$lookup': {
         'from': 'recipes', 
         'localField': 'recipe', 
@@ -82,7 +44,7 @@ const compactPlanner: Controller<null, CompactWeeklyPlanner> = db => req => prev
     }, {
       '$unwind': {
         'path': '$recipe'
-      }, 
+      }
     }, {
       '$project': {
         'recipe': {
@@ -95,6 +57,7 @@ const compactPlanner: Controller<null, CompactWeeklyPlanner> = db => req => prev
     }
   ]).then(plans => plans.reduce((planner, plan) => {
     const date = moment(plan.date);
+    console.log(plan);
     return {
       ...planner,
       [getWeekDay(date)]: {
@@ -103,7 +66,7 @@ const compactPlanner: Controller<null, CompactWeeklyPlanner> = db => req => prev
         [plan.meal]: plan.recipe
       }
     };
-  }, { week } as CompactWeeklyPlanner))
+  }, { week: moment(from).isoWeek() } as WeeklyPlanner))
 }
 
 const savePlan: Controller<void, PlanDB> = db => req => prevResult => {
@@ -150,10 +113,9 @@ const saveWeekPlanner: Controller<PlannerRequest, IDBDocument<Plan[]>> = db => r
 }
 
 export {
-  getWeekPlanner,
-  completePlanner,
-  compactPlanner,
   savePlan,
   saveWeekPlanner,
-  validatePlanner
+  validatePlanner,
+  validateRange,
+  getPlannerByRange
 }

+ 2 - 4
ktchn/src/planner/routes.ts

@@ -2,7 +2,7 @@ import { Router } from 'express';
 import mongoService, { IMongoService } from '../mongo';
 import MongoClient from 'mongodb';
 import { chainP } from '../promise-all-middleware';
-import { getWeekPlanner, completePlanner, compactPlanner, savePlan, saveWeekPlanner, validatePlanner } from './controller';
+import { savePlan, saveWeekPlanner, validatePlanner, validateRange, getPlannerByRange } from './controller';
 
 class PlannerRoutes {
   public router: Router;
@@ -16,9 +16,7 @@ class PlannerRoutes {
 
   private init() {
     this.router.get('/all/');
-    this.router.get('/week/:week', chainP([getWeekPlanner(this.PlannerDB)]));
-    this.router.get('/week/:week/complete', chainP([completePlanner(this.PlannerDB)]));
-    this.router.get('/week/:week/compact', chainP([compactPlanner(this.PlannerDB)]));
+    this.router.get('/week/:from/:to', chainP([validateRange(this.PlannerDB), getPlannerByRange(this.PlannerDB)]))
     this.router.post('/week', chainP([validatePlanner(this.PlannerDB), saveWeekPlanner(this.PlannerDB)]));
     this.router.post('/day', chainP([savePlan(this.PlannerDB)]));
   }

+ 14 - 11
recipes/src/containers/Planner/actions.ts

@@ -3,6 +3,7 @@ import { Meal, RecipePlan, Weekday, DBPlanner, PlannerMode, WeekPlan, DBDayPlan
 import { Dispatch, ActionCreator, Action } from 'redux';
 import { getPlanner, savePlanner } from './services'
 import { ThunkAction } from 'redux-thunk';
+import { Moment } from 'moment';
 
 export const ADD_TO_BACKLOG = 'ADD_TO_BACKLOG';
 export const REMOVE_FROM_BACKLOG = 'REMOVE_FROM_BACKLOG';
@@ -64,11 +65,13 @@ const removeMeal = (day: Weekday, meal: Meal): RemoveMealAction => ({
 });
 
 export interface RequestPlannerAction extends Action<'REQUEST_PLANNER'> {
-  week: number
+  from: Moment,
+  to: Moment
 }
-const requestPlanner = (week: number): RequestPlannerAction => ({
+const requestPlanner = (from: Moment, to: Moment): RequestPlannerAction => ({
   type: REQUEST_PLANNER,
-  week
+  from,
+  to
 })
 
 export interface ReceivePlannerAction extends Action<'RECEIVE_PLANNER'>{
@@ -83,13 +86,13 @@ export const fetchPlannerActionCreator: ActionCreator<
   ThunkAction<
     Promise<ReceivePlannerAction>,
     DBPlanner,
-    number,
+    {from: Moment, to: Moment},
     ReceivePlannerAction
   >
-> = (week: number) => {
+> = (from: Moment, to: Moment) => {
   return async (dispatch: Dispatch) => {
-    dispatch(requestPlanner(week));
-    const planner = await getPlanner(week);
+    dispatch(requestPlanner(from, to));
+    const planner = await getPlanner(from, to);
     return dispatch(receivePlanner(planner))
   }
 }
@@ -110,10 +113,10 @@ export const editPlanner = (): EditPlannerAction => ({
 
 export interface PendingSavePlannerAction extends Action<'PENDING_SAVE_PLANNER'> {
   planner: WeekPlan,
-  from: Date,
-  to: Date
+  from: Moment,
+  to: Moment
 }
-export const pendingSavePlanner = (planner: WeekPlan, from: Date, to: Date): PendingSavePlannerAction => ({
+export const pendingSavePlanner = (planner: WeekPlan, from: Moment, to: Moment): PendingSavePlannerAction => ({
   type: PENDING_SAVE_PLANNER,
   planner,
   from,
@@ -143,7 +146,7 @@ export const savePlannerActionCreator: ActionCreator<
     WeekPlan,
     ConfirmSavePlannerAction|RejectSavePlannerAction
   >
-> = (weekplan: WeekPlan, from: Date, to: Date) => {
+> = (weekplan: WeekPlan, from: Moment, to: Moment) => {
   return async (dispatch: Dispatch) => {
     dispatch(pendingSavePlanner(weekplan, from, to))
     try {

+ 4 - 4
recipes/src/containers/Planner/index.tsx

@@ -6,7 +6,7 @@ import { connect } from 'react-redux';
 import { PlannerState, Weekday, Meal, DayPlan, PlannerMode, RecipePlan, WeekPlan } from 'types/planner';
 import Card from 'components/Card';
 import PlannerActions, { fetchPlannerActionCreator, PlannerActions as PlannerActionsTypes, savePlannerActionCreator } from './actions';
-import moment from 'moment';
+import moment, { Moment } from 'moment';
 import { DragDropContext, Droppable, Draggable, DropResult, OnDragEndResponder } from 'react-beautiful-dnd';
 import './styles.scss';
 import { getWeekDay } from 'services/time';
@@ -35,7 +35,7 @@ class PlannerContainer extends Component<PlannerContainerProps, PlannerContainer
   }
 
   componentDidMount() {
-    this.props.fetch(this.props.week);
+    this.props.fetch(this.props.from, this.props.to);
   }
 
   componentDidUpdate() {
@@ -210,8 +210,8 @@ const mapStateToProps = (state: AppState) => {
 }
 
 const mapDispatchToProps = (dispatch: ThunkDispatch<AppState, any, any>) => ({
-  fetch: (week: number) => dispatch(fetchPlannerActionCreator(week)),
-  save: (plan: WeekPlan, from: Date, to: Date) => dispatch(savePlannerActionCreator(plan, from, to)),
+  fetch: (from: Moment, to: Moment) => dispatch(fetchPlannerActionCreator(from, to)),
+  save: (plan: WeekPlan, from: Moment, to: Moment) => dispatch(savePlannerActionCreator(plan, from, to)),
   ...bindActionCreators(PlannerActions, dispatch)
 })
 

+ 3 - 3
recipes/src/containers/Planner/reducers.ts

@@ -86,9 +86,9 @@ const PlannerReducer: Reducer<PlannerState, PlannerActions> = (
     case 'REQUEST_PLANNER':
       return {
         ...state,
-        week: action.week,
-        from: mkWeekDay(1, action.week),
-        to: mkWeekDay(7, action.week),
+        week: getWeekNumber(action.from),
+        from: action.from,
+        to: action.to,
         isFetching: true,
       }
     case 'RECEIVE_PLANNER':

+ 9 - 8
recipes/src/containers/Planner/services.ts

@@ -1,6 +1,7 @@
+import { shortDate } from 'services/time';
 import axios, { AxiosPromise } from 'axios';
 import { DBPlanner, DBDayPlan, WeekPlan, Weekday, Meal, DayPlan } from 'types/planner';
-import moment from 'moment';
+import moment, { Moment } from 'moment';
 
 //@ts-ignore
 const PLANNER: string = process.env.REACT_APP_API_PLANNER;
@@ -25,20 +26,20 @@ const toDBPlan = (weekplan: WeekPlan) => {
     ]
   }, [] as Array<DBDayPlan>)
 }
-export const getPlanner = (week: number): Promise<DBPlanner> =>
-  axios.get(`${PLANNER}/week/${week}/compact`)
-  .then(response => response.data)
 
-export const savePlanner = (weekPlan: WeekPlan, from: Date, to: Date): Promise<Array<DBDayPlan>> => {
+export const getPlanner = (from: Moment, to: Moment): Promise<DBPlanner> => 
+  axios.get(`${PLANNER}/week/${shortDate(from)}/${shortDate(to)}`).then(response => response.data);
+
+export const savePlanner = (weekPlan: WeekPlan, from: Moment, to: Moment): Promise<Array<DBDayPlan>> => {
   return axios.post(`${PLANNER}/week`, {
     planner: toDBPlan(weekPlan),
-    from,
-    to,
+    from: shortDate(from),
+    to: shortDate(to),
   })
     .then(response => response.data)
 }
 
 export default {
   getPlanner,
-  savePlanner
+  savePlanner,
 }

+ 5 - 2
recipes/src/services/time.ts

@@ -8,7 +8,7 @@ export const mkWeekDay = (day: string | number, week?: number): Moment => {
   return date.isoWeekday(day);
 };
 
-export const getWeekNumber = (): number => moment().isoWeek();
+export const getWeekNumber = (date?: string|Date|Moment): number => moment(date).isoWeek();
 
 export const getWeekDay = (day: Moment): Weekday => day.format('dddd').toLowerCase() as Weekday;
 
@@ -16,9 +16,12 @@ export const mkWeekData = (weekNumber: number): [Weekday, string][] => mkWeek().
   [ day, moment().week(weekNumber).isoWeekday(day).format() ]
 ))
 
+export const shortDate = (date: Moment): string => date.format('YYYY-MM-DD')
+
 export default {
   mkWeekDay,
   getWeekNumber,
   getWeekDay,
-  mkWeekData
+  mkWeekData,
+  shortDate,
 }