Pārlūkot izejas kodu

Add Save option in planner

Tatiana Inama 7 gadi atpakaļ
vecāks
revīzija
695cc7b2c5

+ 6 - 1
ktchn/src/planner/controller.ts

@@ -113,7 +113,12 @@ const savePlan: Controller<void, PlanDB> = db => req => prevResult => {
 const saveManyPlans: Controller<void, PlanDB[]> = db => req => prev => {
   const mbPlanner = req.body;
   if (mbPlanner.filter) {
-    return db.insertMany(mbPlanner.filter(validatePlan))
+    const valid = mbPlanner.filter(validatePlan);
+    if (valid.length) {
+      return db.insertMany(valid)
+    } else {
+      return Promise.reject('Data did not have required fields: date, week, meal, ')
+    }
   } else {
     return Promise.reject('Invalid type: body content must be a Plan Array')
   }

+ 56 - 3
recipes/src/containers/Planner/actions.ts

@@ -1,8 +1,9 @@
 import { DBRecipe } from 'types/recipes';
-import { Meal, RecipePlan, Weekday, DBPlanner, PlannerMode } from 'types/planner';
+import { Meal, RecipePlan, Weekday, DBPlanner, PlannerMode, WeekPlan, DBDayPlan } from 'types/planner';
 import { Dispatch, ActionCreator, Action } from 'redux';
-import { getPlanner } from './services'
+import { getPlanner, savePlanner } from './services'
 import { ThunkAction } from 'redux-thunk';
+import { async } from 'q';
 
 export const ADD_TO_BACKLOG = 'ADD_TO_BACKLOG';
 export const REMOVE_FROM_BACKLOG = 'REMOVE_FROM_BACKLOG';
@@ -14,6 +15,10 @@ export const RECEIVE_PLANNER = 'RECEIVE_PLANNER';
 
 export const CHANGE_PLANNER_MODE = 'CHANGE_PLANNER_MODE';
 
+export const PENDING_SAVE_PLANNER = 'PENDING_SAVE_PLANNER';
+export const CONFIRM_SAVE_PLANNER = 'CONFIRM_SAVE_PLANNER';
+export const REJECT_SAVE_PLANNER = 'REJECT_SAVE_PLANNER';
+
 export interface AddToBacklogAction extends Action<'ADD_TO_BACKLOG'> {
   recipe: {
     _id: string,
@@ -97,6 +102,50 @@ export const changePlannerMode = (mode: PlannerMode): ChangePlannerModeAction =>
   mode,
 });
 
+export interface PendingSavePlannerAction extends Action<'PENDING_SAVE_PLANNER'> {
+  planner: WeekPlan
+}
+export const pendingSavePlanner = (planner: WeekPlan): PendingSavePlannerAction => ({
+  type: PENDING_SAVE_PLANNER,
+  planner,
+})
+
+export interface ConfirmSavePlannerAction extends Action<'CONFIRM_SAVE_PLANNER'> {
+  result: DBDayPlan[]
+}
+export const confirmSavePlanner = (result: DBDayPlan[]): ConfirmSavePlannerAction => ({
+  type: CONFIRM_SAVE_PLANNER,
+  result
+})
+
+export interface RejectSavePlannerAction extends Action<'REJECT_SAVE_PLANNER'> {
+  error: Error
+}
+export const rejectSavePlanner = (error: Error): RejectSavePlannerAction => ({
+  type: REJECT_SAVE_PLANNER,
+  error,
+})
+
+export const savePlannerActionCreator: ActionCreator<
+  ThunkAction<
+    Promise<ConfirmSavePlannerAction|RejectSavePlannerAction>,
+    DBDayPlan[],
+    WeekPlan,
+    ConfirmSavePlannerAction|RejectSavePlannerAction
+  >
+> = (weekplan: WeekPlan) => {
+  return async (dispatch: Dispatch) => {
+    dispatch(pendingSavePlanner(weekplan))
+    try {
+      const result = await savePlanner(weekplan);
+      return dispatch(confirmSavePlanner(result))
+    } catch(error) {
+      return dispatch(rejectSavePlanner(error))
+    }
+  }
+}
+
+
 export type PlannerActions =
   AddToBacklogAction |
   RemoveFromBacklogAction |
@@ -104,7 +153,10 @@ export type PlannerActions =
   RemoveMealAction |
   RequestPlannerAction |
   ReceivePlannerAction |
-  ChangePlannerModeAction;
+  ChangePlannerModeAction |
+  PendingSavePlannerAction |
+  ConfirmSavePlannerAction |
+  RejectSavePlannerAction;
 
 export default {
   addToBacklog,
@@ -112,4 +164,5 @@ export default {
   assignToDay,
   removeMeal,
   changePlannerMode,
+  
 }

+ 9 - 5
recipes/src/containers/Planner/index.tsx

@@ -4,9 +4,8 @@ import Navbar from 'components/Navbar';
 import { AppState } from 'store/configureStore';
 import { connect } from 'react-redux';
 import { PlannerState, Weekday, Meal, DayPlan, PlannerMode, RecipePlan, WeekPlan } from 'types/planner';
-import { Grid, Row, Cell } from "@material/react-layout-grid";
 import Card from 'components/Card';
-import PlannerActions, { fetchPlannerActionCreator, PlannerActions as PlannerActionsTypes } from './actions';
+import PlannerActions, { fetchPlannerActionCreator, PlannerActions as PlannerActionsTypes, savePlannerActionCreator } from './actions';
 import moment from 'moment';
 import { DragDropContext, Droppable, Draggable, DropResult, OnDragEndResponder } from 'react-beautiful-dnd';
 import './styles.scss';
@@ -18,7 +17,8 @@ import { bindActionCreators } from 'redux';
 type Actions = typeof PlannerActions
 
 interface PlannerContainerProps extends RouteComponentProps, PlannerState, Actions {
-  fetch: typeof fetchPlannerActionCreator
+  fetch: typeof fetchPlannerActionCreator,
+  save: typeof savePlannerActionCreator
 }
 
 interface PlannerContainerState {
@@ -65,8 +65,11 @@ class PlannerContainer extends Component<PlannerContainerProps, PlannerContainer
           {
             this.props.mode === 'view' ? (
               <Button outlined raised onClick={() => this.changeMode('edit')}>Edit</Button>
-              ) : (  
-              <Button outlined raised onClick={() => this.changeMode('view')}>Save</Button>
+              ) : (
+              <Button outlined raised onClick={() => {
+                this.props.save(this.props.planner)
+                this.changeMode('view')
+              }}>Save</Button>
             )
           }
         </Navbar>
@@ -217,6 +220,7 @@ const mapStateToProps = (state: AppState) => {
 
 const mapDispatchToProps = (dispatch: ThunkDispatch<AppState, any, any>) => ({
   fetch: (week: number) => dispatch(fetchPlannerActionCreator(week)),
+  save: (plan: WeekPlan) => dispatch(savePlannerActionCreator(plan)),
   ...bindActionCreators(PlannerActions, dispatch)
 })
 

+ 17 - 0
recipes/src/containers/Planner/reducers.ts

@@ -7,6 +7,7 @@ import { merge, uniqBy } from 'ramda';
 const initialState: PlannerState = {
   mode: 'view',
   isFetching: false,
+  saving: false,
   from: mkWeekDay(1),
   to: mkWeekDay(7),
   week: getWeekNumber(),
@@ -99,6 +100,22 @@ const PlannerReducer: Reducer<PlannerState, PlannerActions> = (
         ...state,
         mode: action.mode
       }
+    case 'PENDING_SAVE_PLANNER':
+      return {
+        ...state,
+        saving: true
+      }
+    case 'CONFIRM_SAVE_PLANNER':
+      return {
+        ...state,
+        saving: false
+      }
+    case 'REJECT_SAVE_PLANNER':
+      return {
+        ...state,
+        saving: false,
+        error: action.error.message
+      }
     default:
       return state
   }

+ 27 - 2
recipes/src/containers/Planner/services.ts

@@ -1,13 +1,38 @@
 import axios, { AxiosPromise } from 'axios';
-import { DBPlanner } from 'types/planner';
+import { DBPlanner, DBDayPlan, WeekPlan, Weekday, Meal, DayPlan } from 'types/planner';
 
 //@ts-ignore
 const PLANNER: string = process.env.REACT_APP_API_PLANNER;
 
+const toDBPlan = (weekplan: WeekPlan) => {
+  const planner = Object.keys(weekplan).map((weekday) => weekplan[weekday as Weekday]);
+  const mkPlan = (day: DayPlan, meal: Meal): Array<DBDayPlan> => {
+    const dish = day[meal];
+    return dish ? [{
+      week: day.date.week(),
+      recipe: dish._id,
+      meal: meal,
+      date: day.date.format()
+    }] : []
+  } 
+  return planner.reduce((acc, day)=> {
+    return [
+      ...acc,
+      ...mkPlan(day, 'lunch'),
+      ...mkPlan(day, 'dinner')
+    ]
+  }, [] 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): Promise<Array<DBDayPlan>> => {
+  return axios.post(`${PLANNER}/`, toDBPlan(weekPlan))
+    .then(response => response.data)
+}
+
 export default {
-  getPlanner
+  getPlanner,
+  savePlanner
 }

+ 8 - 0
recipes/src/types/planner.ts

@@ -31,6 +31,7 @@ export type PlannerMode = 'edit' | 'view';
 export interface PlannerState {
   mode: PlannerMode,
   isFetching: boolean,
+  saving: boolean,
   error?: string,
   week: number,
   from: Moment,
@@ -39,6 +40,13 @@ export interface PlannerState {
   backlog: RecipePlan[]
 }
 
+export interface DBDayPlan {
+  date: string,
+  recipe: string,
+  week: number,
+  meal: Meal
+}
+
 export interface DBPlanner extends WeekPlan {
   week: number,
 }