From c3629581f46e81c49ee6f6340a2bcdd6ad5a4cf3 Mon Sep 17 00:00:00 2001 From: tahmid-saj Date: Sun, 22 Sep 2024 10:50:29 -0400 Subject: [PATCH 1/2] ts config --- package-lock.json | 46 +++++++++++++++++++++++++++++----------------- package.json | 5 +++++ src/custom.d.ts | 6 ++++++ tsconfig.json | 22 ++++++++++++++++++++++ 4 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 src/custom.d.ts create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index 5e43a79..584c590 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,10 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/jest": "^29.5.13", + "@types/node": "^22.5.5", + "@types/react": "^18.3.8", + "@types/react-dom": "^18.3.0", "ag-grid-react": "^31.3.1", "apexcharts": "^3.44.0", "dayjs": "^1.11.11", @@ -45,6 +49,7 @@ "rsuite": "^5.64.1", "sass": "^1.66.1", "styled-components": "^6.1.11", + "typescript": "^5.6.2", "web-vitals": "^2.1.4" }, "peerDependencies": { @@ -8290,9 +8295,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.4.tgz", - "integrity": "sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==", + "version": "29.5.13", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.13.tgz", + "integrity": "sha512-wd+MVEZCHt23V0/L642O5APvspWply/rGY5BcW4SUETo2UzPU3Z26qr8jC2qxpimI2jjx9h7+2cj2FwIr01bXg==", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -8546,9 +8551,12 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "node_modules/@types/node": { - "version": "20.5.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.6.tgz", - "integrity": "sha512-Gi5wRGPbbyOTX+4Y2iULQ27oUPrefaB0PxGQJnfyWN3kvEDGM3mIB5M/gQLmitZf7A9FmLeaqxD3L1CXpm3VKQ==" + "version": "22.5.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz", + "integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==", + "dependencies": { + "undici-types": "~6.19.2" + } }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -8581,18 +8589,18 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", + "version": "18.3.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.8.tgz", + "integrity": "sha512-syBUrW3/XpnW4WJ41Pft+I+aPoDVbrBVQGEnbD7NijDGlVC+8gV/XKRY+7vMDlfPpbwYt0l1vd/Sj8bJGMbs9Q==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", - "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", "dependencies": { "@types/react": "*" } @@ -22288,16 +22296,15 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true, + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/typescript-compare": { @@ -22335,6 +22342,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", diff --git a/package.json b/package.json index 1457025..06bc84b 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,10 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/jest": "^29.5.13", + "@types/node": "^22.5.5", + "@types/react": "^18.3.8", + "@types/react-dom": "^18.3.0", "ag-grid-react": "^31.3.1", "apexcharts": "^3.44.0", "dayjs": "^1.11.11", @@ -44,6 +48,7 @@ "rsuite": "^5.64.1", "sass": "^1.66.1", "styled-components": "^6.1.11", + "typescript": "^5.6.2", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/src/custom.d.ts b/src/custom.d.ts new file mode 100644 index 0000000..1289af9 --- /dev/null +++ b/src/custom.d.ts @@ -0,0 +1,6 @@ +declare module "*.svg" { + import React = require("react") + export const ReactComponent: React.FC> + const src: string; + export default src; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..41e1258 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ES6", + "lib": ["dom", "dom.iterable", "esnext"], + "downlevelIteration": true, + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "allowImportingTsExtensions": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + }, + "include": ["src/*", "src/custom.d.ts"] +} From 62a8c23c89d293875ec85459adef753fff3c614f Mon Sep 17 00:00:00 2001 From: tahmid-saj Date: Sun, 22 Sep 2024 12:42:13 -0400 Subject: [PATCH 2/2] migrating redux to ts --- .../nutrition-tracker.types.ts | 88 +++++++ src/store/middleware/{logger.js => logger.ts} | 5 +- ...cer.toolkit.js => root-reducer.toolkit.ts} | 0 .../{root-reducer.js => root-reducer.ts} | 0 src/store/{root-saga.js => root-saga.ts} | 0 src/store/shared/user/user.action.js | 26 -- src/store/shared/user/user.action.ts | 68 +++++ src/store/shared/user/user.reducer.js | 44 ---- src/store/shared/user/user.reducer.toolkit.js | 19 -- src/store/shared/user/user.reducer.toolkit.ts | 42 +++ src/store/shared/user/user.reducer.ts | 132 ++++++++++ src/store/shared/user/user.saga.js | 114 -------- src/store/shared/user/user.saga.ts | 248 ++++++++++++++++++ src/store/shared/user/user.selector.js | 1 - src/store/shared/user/user.selector.ts | 12 + src/store/shared/user/user.types.js | 17 -- src/store/shared/user/user.types.ts | 35 +++ ....action.js => nutrition-tracker.action.ts} | 142 ++++++---- .../nutrition-tracker.reducer.js | 63 ----- ...s => nutrition-tracker.reducer.toolkit.ts} | 3 +- .../nutrition-tracker.reducer.ts | 147 +++++++++++ ...ector.js => nutrition-tracker.selector.ts} | 4 +- .../nutrition-tracker.types.js | 12 - .../nutrition-tracker.types.ts | 64 +++++ src/store/store.toolkit.js | 14 - src/store/store.toolkit.ts | 30 +++ src/store/{store.js => store.ts} | 8 + src/utils/reducer/reducer.utils.js | 4 - src/utils/reducer/reducer.utils.ts | 39 +++ 29 files changed, 1013 insertions(+), 368 deletions(-) create mode 100644 src/contexts/signed-out/nutrition-tracker/nutrition-tracker.types.ts rename src/store/middleware/{logger.js => logger.ts} (60%) rename src/store/{root-reducer.toolkit.js => root-reducer.toolkit.ts} (100%) rename src/store/{root-reducer.js => root-reducer.ts} (100%) rename src/store/{root-saga.js => root-saga.ts} (100%) delete mode 100644 src/store/shared/user/user.action.js create mode 100644 src/store/shared/user/user.action.ts delete mode 100644 src/store/shared/user/user.reducer.js delete mode 100644 src/store/shared/user/user.reducer.toolkit.js create mode 100644 src/store/shared/user/user.reducer.toolkit.ts create mode 100644 src/store/shared/user/user.reducer.ts delete mode 100644 src/store/shared/user/user.saga.js create mode 100644 src/store/shared/user/user.saga.ts delete mode 100644 src/store/shared/user/user.selector.js create mode 100644 src/store/shared/user/user.selector.ts delete mode 100644 src/store/shared/user/user.types.js create mode 100644 src/store/shared/user/user.types.ts rename src/store/signed-out/nutrition-tracker/{nutrition-tracker.action.js => nutrition-tracker.action.ts} (50%) delete mode 100644 src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.js rename src/store/signed-out/nutrition-tracker/{nutrition-tracker.reducer.toolkit.js => nutrition-tracker.reducer.toolkit.ts} (90%) create mode 100644 src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.ts rename src/store/signed-out/nutrition-tracker/{nutrition-tracker.selector.js => nutrition-tracker.selector.ts} (86%) delete mode 100644 src/store/signed-out/nutrition-tracker/nutrition-tracker.types.js create mode 100644 src/store/signed-out/nutrition-tracker/nutrition-tracker.types.ts delete mode 100644 src/store/store.toolkit.js create mode 100644 src/store/store.toolkit.ts rename src/store/{store.js => store.ts} (89%) delete mode 100644 src/utils/reducer/reducer.utils.js create mode 100644 src/utils/reducer/reducer.utils.ts diff --git a/src/contexts/signed-out/nutrition-tracker/nutrition-tracker.types.ts b/src/contexts/signed-out/nutrition-tracker/nutrition-tracker.types.ts new file mode 100644 index 0000000..4992310 --- /dev/null +++ b/src/contexts/signed-out/nutrition-tracker/nutrition-tracker.types.ts @@ -0,0 +1,88 @@ +import { ReactNode } from "react"; + +// nutrition tracker types + +export interface NutritionTrackedDayContextType { + nutritionTrackedDays: NutritionTrackedDay[]; + formInputMicronutrients: FormInputMicronutrient[]; + selectedNutritionTrackedDay: SelectedNutritionTrackedDay; + filterConditions: FilterConditions; + nutritionTrackedDaysView: NutritionTrackedDaysView; + scheduledNutritionTrackedDaysView: ScheduledNutritionTrackedDaysView; + + addDayTracked: (trackedDayInfo: NutritionTrackedDay) => void; + updateDayTracked: (updatedTrackedDayInfo: NutritionTrackedDay) => void; + getDayTracked: (trackedDay: string | Date) => void; + + selectedScheduledNutritionTrackedDay: (trackedDay: string | Date) => void; + + dayTrackedSearchResult: NutritionTrackedDay; + + addFormInputMicronutrients: () => void; + updateFormInputMicronutrients: (micronutrient: Micronutrient, micronutrientIndex: number) => void; + deleteFormInputMicronutrients: (micronutrientIndex: number) => void; + + addDayTrackedFromPrediction: (predictionNutritionInfo: PredictionNutritionInfo) => void; + + nutritionTrackedDaysSummary: NutritionTrackedDaysSummary; + + filterDayTracked: (filterConditions: FilterConditions) => void; + removeDayTracked: (trackedDay: string | Date) => void; + clearDayTrackedFilter: () => void; +} + +export interface NutritionTrackedDayProviderProps { + children: ReactNode +} + +export type NutritionTrackedDay = { + dateTracked: string; + calories: number; + macronutrients: Macronutrient[]; + micronutrients: Micronutrient[]; +} + +export type Macronutrient = { + carbohydrates: number; + protein: number; + fat: number; +} + +export type Micronutrient = { + name: string; + amount: number; + unit: string; +} + +export type FormInputMicronutrient = { + name: string; + amount: number; + unit: string; +} + +export type SelectedNutritionTrackedDay = string | Date | null; + +export type FilterConditions = { + filterStartDate?: string; + filterEndDate?: string; +} + +export type NutritionTrackedDaysView = NutritionTrackedDay[]; + +export type ScheduledNutritionTrackedDaysView = NutritionTrackedDay + +export type DayTrackedSearchResult = NutritionTrackedDay; + +export type NutritionTrackedDaysSummary = { + averageDailyCaloriesConsumption: number; + averageDailyCarbohydratesConsumption: number; + averageDailyProteinConsumption: number; + averageDailyFatConsumption: number; +} + +export type PredictionNutritionInfo = { + dateTracked: string | Date; + calories: number; + macronutrients: Macronutrient[]; + micronutrients: Micronutrient[]; +} \ No newline at end of file diff --git a/src/store/middleware/logger.js b/src/store/middleware/logger.ts similarity index 60% rename from src/store/middleware/logger.js rename to src/store/middleware/logger.ts index ecafac8..155a91c 100644 --- a/src/store/middleware/logger.js +++ b/src/store/middleware/logger.ts @@ -1,6 +1,9 @@ // redux middlewares -export const loggerMiddleware = (store) => (next) => (action) => { +import { Middleware } from "redux" +import { RootState } from "../store" + +export const loggerMiddleware: Middleware<{}, RootState> = (store) => (next) => (action: any) => { if (!action.type) { return next(action) } diff --git a/src/store/root-reducer.toolkit.js b/src/store/root-reducer.toolkit.ts similarity index 100% rename from src/store/root-reducer.toolkit.js rename to src/store/root-reducer.toolkit.ts diff --git a/src/store/root-reducer.js b/src/store/root-reducer.ts similarity index 100% rename from src/store/root-reducer.js rename to src/store/root-reducer.ts diff --git a/src/store/root-saga.js b/src/store/root-saga.ts similarity index 100% rename from src/store/root-saga.js rename to src/store/root-saga.ts diff --git a/src/store/shared/user/user.action.js b/src/store/shared/user/user.action.js deleted file mode 100644 index d36de6d..0000000 --- a/src/store/shared/user/user.action.js +++ /dev/null @@ -1,26 +0,0 @@ -import { createAction } from "../../../utils/reducer/reducer.utils"; -import { USER_ACTION_TYPES } from "./user.types" - -export const setCurrentUser = (user) => createAction(USER_ACTION_TYPES.SET_CURRENT_USER, user) - -export const checkUserSession = () => createAction(USER_ACTION_TYPES.CHECK_USER_SESSION) - -export const googleSignInStart = () => createAction(USER_ACTION_TYPES.GOOGLE_SIGN_IN_START) - -export const emailSignInStart = (email, password) => createAction(USER_ACTION_TYPES.EMAIL_SIGN_IN_START, { email, password }) - -export const signInSuccess = (user) => createAction(USER_ACTION_TYPES.SIGN_IN_SUCCESS, user) - -export const signInFailed = (error) => createAction(USER_ACTION_TYPES.SIGN_IN_FAILED, error) - -export const signUpStart = (email, password, displayName) => createAction(USER_ACTION_TYPES.SIGN_UP_START, { email, password, displayName }) - -export const signUpSuccess = (user, additionalDetails) => createAction(USER_ACTION_TYPES.SIGN_UP_SUCCESS, { user, additionalDetails }) - -export const signUpFailed = (error) => createAction(USER_ACTION_TYPES.SIGN_UP_FAILED, error) - -export const signOutStart = () => createAction(USER_ACTION_TYPES.SIGN_OUT_START) - -export const signOutSuccess = () => createAction(USER_ACTION_TYPES.SIGN_OUT_SUCCESS) - -export const signOutFailed = (error) => createAction(USER_ACTION_TYPES.SIGN_OUT_FAILED) \ No newline at end of file diff --git a/src/store/shared/user/user.action.ts b/src/store/shared/user/user.action.ts new file mode 100644 index 0000000..a1136e0 --- /dev/null +++ b/src/store/shared/user/user.action.ts @@ -0,0 +1,68 @@ +import { User } from "firebase/auth"; +import { AdditionalInformation, UserData } from "../../../utils/firebase/firebase.utils"; +import { Action, ActionWithPayload, createAction, withMatcher } from "../../../utils/reducer/reducer.utils"; +import { USER_ACTION_TYPES } from "./user.types" + +export type CheckUserSession = Action +export type SetCurrentUser = ActionWithPayload +export type GoogleSignInStart = Action +export type EmailSignInStart = ActionWithPayload +export type SignInSuccess = ActionWithPayload +export type SignInFailed = ActionWithPayload +export type SignUpStart = ActionWithPayload +export type SignUpSuccess = ActionWithPayload +export type SignUpFailed = ActionWithPayload +export type SignOutStart = Action +export type SignOutSuccess = Action +export type SignOutFailed = ActionWithPayload + +export const setCurrentUser = withMatcher((user: UserData): SetCurrentUser => createAction(USER_ACTION_TYPES.SET_CURRENT_USER, user)) + +export const checkUserSession = withMatcher((): CheckUserSession => createAction(USER_ACTION_TYPES.CHECK_USER_SESSION)) + +export const googleSignInStart = withMatcher((): GoogleSignInStart => createAction(USER_ACTION_TYPES.GOOGLE_SIGN_IN_START)) + +export const emailSignInStart = withMatcher((email: string, password: string): EmailSignInStart => createAction(USER_ACTION_TYPES.EMAIL_SIGN_IN_START, { email, password })) + +export const signInSuccess = withMatcher((user: UserData): SignInSuccess => createAction(USER_ACTION_TYPES.SIGN_IN_SUCCESS, user)) + +export const signInFailed = withMatcher((error: Error): SignInFailed => createAction(USER_ACTION_TYPES.SIGN_IN_FAILED, error)) + +export const signUpStart = withMatcher((email: string, password: string, displayName: string): SignUpStart => createAction(USER_ACTION_TYPES.SIGN_UP_START, { email, password, displayName })) + +export const signUpSuccess = withMatcher((user: User, additionalDetails: AdditionalInformation): SignUpSuccess => createAction(USER_ACTION_TYPES.SIGN_UP_SUCCESS, { user, additionalDetails })) + +export const signUpFailed = withMatcher((error: Error): SignUpFailed => createAction(USER_ACTION_TYPES.SIGN_UP_FAILED, error)) + +export const signOutStart = withMatcher((): SignOutStart => createAction(USER_ACTION_TYPES.SIGN_OUT_START)) + +export const signOutSuccess = withMatcher((): SignOutSuccess => createAction(USER_ACTION_TYPES.SIGN_OUT_SUCCESS)) + +export const signOutFailed = withMatcher((error: Error): SignOutFailed => createAction(USER_ACTION_TYPES.SIGN_OUT_FAILED, error)) + +// import { createAction } from "../../../utils/reducer/reducer.utils"; +// import { USER_ACTION_TYPES } from "./user.types" + +// export const setCurrentUser = (user) => createAction(USER_ACTION_TYPES.SET_CURRENT_USER, user) + +// export const checkUserSession = () => createAction(USER_ACTION_TYPES.CHECK_USER_SESSION) + +// export const googleSignInStart = () => createAction(USER_ACTION_TYPES.GOOGLE_SIGN_IN_START) + +// export const emailSignInStart = (email, password) => createAction(USER_ACTION_TYPES.EMAIL_SIGN_IN_START, { email, password }) + +// export const signInSuccess = (user) => createAction(USER_ACTION_TYPES.SIGN_IN_SUCCESS, user) + +// export const signInFailed = (error) => createAction(USER_ACTION_TYPES.SIGN_IN_FAILED, error) + +// export const signUpStart = (email, password, displayName) => createAction(USER_ACTION_TYPES.SIGN_UP_START, { email, password, displayName }) + +// export const signUpSuccess = (user, additionalDetails) => createAction(USER_ACTION_TYPES.SIGN_UP_SUCCESS, { user, additionalDetails }) + +// export const signUpFailed = (error) => createAction(USER_ACTION_TYPES.SIGN_UP_FAILED, error) + +// export const signOutStart = () => createAction(USER_ACTION_TYPES.SIGN_OUT_START) + +// export const signOutSuccess = () => createAction(USER_ACTION_TYPES.SIGN_OUT_SUCCESS) + +// export const signOutFailed = (error) => createAction(USER_ACTION_TYPES.SIGN_OUT_FAILED) \ No newline at end of file diff --git a/src/store/shared/user/user.reducer.js b/src/store/shared/user/user.reducer.js deleted file mode 100644 index d774a14..0000000 --- a/src/store/shared/user/user.reducer.js +++ /dev/null @@ -1,44 +0,0 @@ -import { USER_ACTION_TYPES } from "./user.types"; - -const INITIAL_STATE = { - currentUser: null, - isLoading: false, - error: null -} - -export const userReducer = (state=INITIAL_STATE, action) => { - const { type, payload } = action - - switch(type) { - case USER_ACTION_TYPES.GOOGLE_SIGN_IN_START: - case USER_ACTION_TYPES.EMAIL_SIGN_IN_START: - case USER_ACTION_TYPES.SIGN_UP_START: - case USER_ACTION_TYPES.SIGN_OUT_START: - return { - ...state, - isLoading: true - } - case USER_ACTION_TYPES.SIGN_IN_SUCCESS: - return { - ...state, - currentUser: payload, - isLoading: false - } - case USER_ACTION_TYPES.SIGN_OUT_SUCCESS: - return { - ...state, - currentUser: null, - isLoading: false - } - case USER_ACTION_TYPES.SIGN_IN_FAILED: - case USER_ACTION_TYPES.SIGN_UP_FAILED: - case USER_ACTION_TYPES.SIGN_OUT_FAILED: - return { - ...state, - error: payload, - isLoading: false - } - default: - return state - } -} \ No newline at end of file diff --git a/src/store/shared/user/user.reducer.toolkit.js b/src/store/shared/user/user.reducer.toolkit.js deleted file mode 100644 index 56e7c22..0000000 --- a/src/store/shared/user/user.reducer.toolkit.js +++ /dev/null @@ -1,19 +0,0 @@ -import { createSlice } from "@reduxjs/toolkit"; - -const INITIAL_STATE = { - currentUser: null -} - -export const userSlice = createSlice({ - name: "user", - initialState: INITIAL_STATE, - reducers: { - setCurrentUser(state, action) { - state.currentUser = action.payload - } - } -}) - -export const { setCurrentUser } = userSlice.actions - -export const userReducer = userSlice.reducer \ No newline at end of file diff --git a/src/store/shared/user/user.reducer.toolkit.ts b/src/store/shared/user/user.reducer.toolkit.ts new file mode 100644 index 0000000..816d4ee --- /dev/null +++ b/src/store/shared/user/user.reducer.toolkit.ts @@ -0,0 +1,42 @@ +import { createSlice } from "@reduxjs/toolkit"; +import { UserState } from "./user.reducer"; + +const INITIAL_STATE: UserState = { + currentUser: null, + isLoading: false, + error: null +} + +export const userSlice = createSlice({ + name: "user", + initialState: INITIAL_STATE, + reducers: { + setCurrentUser(state, action) { + state.currentUser = action.payload + } + } +}) + +export const { setCurrentUser } = userSlice.actions + +export const userReducer = userSlice.reducer + +// import { createSlice } from "@reduxjs/toolkit"; + +// const INITIAL_STATE = { +// currentUser: null +// } + +// export const userSlice = createSlice({ +// name: "user", +// initialState: INITIAL_STATE, +// reducers: { +// setCurrentUser(state, action) { +// state.currentUser = action.payload +// } +// } +// }) + +// export const { setCurrentUser } = userSlice.actions + +// export const userReducer = userSlice.reducer \ No newline at end of file diff --git a/src/store/shared/user/user.reducer.ts b/src/store/shared/user/user.reducer.ts new file mode 100644 index 0000000..80bfa10 --- /dev/null +++ b/src/store/shared/user/user.reducer.ts @@ -0,0 +1,132 @@ +import { USER_ACTION_TYPES } from "./user.types"; +import { UserData } from "../../../utils/firebase/firebase.utils"; +import { AnyAction } from "redux"; +import { emailSignInStart, googleSignInStart, signInFailed, signInSuccess, signOutFailed, signOutStart, signOutSuccess, signUpFailed, signUpStart } from "./user.action"; + +export type UserState = { + readonly currentUser: UserData | null | undefined; + readonly isLoading: Boolean | null | undefined; + readonly error: Error | null | undefined; +} + +const INITIAL_STATE: UserState = { + currentUser: null, + isLoading: false, + error: null +} + +export const userReducer = (state=INITIAL_STATE, action: AnyAction): UserState => { + if (googleSignInStart.match(action) || emailSignInStart.match(action) || + signUpStart.match(action) || signOutStart.match(action)) { + return { + ...state, + isLoading: true + } + } + + if (signInSuccess.match(action)) { + return { + ...state, + currentUser: action.payload, + isLoading: false + } + } + + if (signOutSuccess.match(action)) { + return { + ...state, + currentUser: null, + isLoading: false + } + } + + if (signInFailed.match(action) || signUpFailed.match(action) || signOutFailed.match(action)) { + return { + ...state, + error: action.payload, + isLoading: false + } + } + + return state + + // const { type, payload } = action + + // switch(type) { + // case USER_ACTION_TYPES.GOOGLE_SIGN_IN_START: + // case USER_ACTION_TYPES.EMAIL_SIGN_IN_START: + // case USER_ACTION_TYPES.SIGN_UP_START: + // case USER_ACTION_TYPES.SIGN_OUT_START: + // return { + // ...state, + // isLoading: true + // } + // case USER_ACTION_TYPES.SIGN_IN_SUCCESS: + // return { + // ...state, + // currentUser: payload, + // isLoading: false + // } + // case USER_ACTION_TYPES.SIGN_OUT_SUCCESS: + // return { + // ...state, + // currentUser: null, + // isLoading: false + // } + // case USER_ACTION_TYPES.SIGN_IN_FAILED: + // case USER_ACTION_TYPES.SIGN_UP_FAILED: + // case USER_ACTION_TYPES.SIGN_OUT_FAILED: + // return { + // ...state, + // error: payload, + // isLoading: false + // } + // default: + // return state + // } +} + +// import { USER_ACTION_TYPES } from "./user.types"; + +// const INITIAL_STATE = { +// currentUser: null, +// isLoading: false, +// error: null +// } + +// export const userReducer = (state=INITIAL_STATE, action) => { +// const { type, payload } = action + +// switch(type) { +// case USER_ACTION_TYPES.GOOGLE_SIGN_IN_START: +// case USER_ACTION_TYPES.EMAIL_SIGN_IN_START: +// case USER_ACTION_TYPES.SIGN_UP_START: +// case USER_ACTION_TYPES.SIGN_OUT_START: +// return { +// ...state, +// isLoading: true +// } +// case USER_ACTION_TYPES.SIGN_IN_SUCCESS: +// return { +// ...state, +// currentUser: payload, +// isLoading: false +// } +// case USER_ACTION_TYPES.SIGN_OUT_SUCCESS: +// return { +// ...state, +// currentUser: null, +// isLoading: false +// } +// case USER_ACTION_TYPES.SIGN_IN_FAILED: +// case USER_ACTION_TYPES.SIGN_UP_FAILED: +// case USER_ACTION_TYPES.SIGN_OUT_FAILED: +// return { +// ...state, +// error: payload, +// isLoading: false +// } +// default: +// return state +// } +// } \ No newline at end of file diff --git a/src/store/shared/user/user.saga.js b/src/store/shared/user/user.saga.js deleted file mode 100644 index 55d05bf..0000000 --- a/src/store/shared/user/user.saga.js +++ /dev/null @@ -1,114 +0,0 @@ -import { takeLatest, put, all, call } from "redux-saga/effects"; -import { USER_ACTION_TYPES } from "./user.types"; -import { signInSuccess, signInFailed, - signUpStart, signUpSuccess, signUpFailed, - signOutSuccess, signOutFailed -} from "./user.action"; - -import { getCurrentUser, - createUserDocumentFromAuth, - signInWithGooglePopup, - signInAuthUserWithEmailAndPassword, - createAuthUserWithEmailAndPassword, - signOutUser -} from "../../../utils/firebase/firebase.utils" - -// helper functions -export function* getSnapshotFromUserAuth(userAuth, additionalDetails) { - try { - const userSnapshot = yield call(createUserDocumentFromAuth, userAuth, additionalDetails) - yield put(signInSuccess({ uid: userSnapshot.id, ...userSnapshot.data() })) - } catch (error) { - yield put(signInFailed(error)) - } -} - -export function* isUserAuthenticated() { - try { - const userAuth = yield call(getCurrentUser) - if (!userAuth) return - yield call(getSnapshotFromUserAuth, userAuth) - } catch (error) { - yield put(signInFailed(error)) - } -} - -export function* signInWithGoogle() { - try { - const { user } = yield call(signInWithGooglePopup) - yield call(getSnapshotFromUserAuth, user) - } catch (error) { - yield put(signInFailed(error)) - } -} - -export function* signInWithEmail({ payload: { email, password } }) { - try { - const { user } = yield call( - signInAuthUserWithEmailAndPassword, - email, password - ) - yield call(getSnapshotFromUserAuth, user) - } catch (error) { - yield put(signInFailed(error)) - } -} - -export function* signUp({ payload: { email, password, displayName } }) { - try { - const { user } = yield call(createAuthUserWithEmailAndPassword, email, password) - yield put(signUpSuccess(user, { displayName })) - } catch (error) { - yield put(signUpFailed(error)) - } -} - -export function* signInAfterSignUp({ payload: { user, additionalDetails } }) { - yield call(getSnapshotFromUserAuth, user, additionalDetails) -} - -export function* signOut() { - try { - yield call(signOutUser) - yield put(signOutSuccess()) - } catch (error) { - yield put(signOutFailed(error)) - } -} - -// callbacks on actions -export function* onCheckUserSession() { - yield takeLatest(USER_ACTION_TYPES.CHECK_USER_SESSION, isUserAuthenticated) -} - -export function* onGoogleSignInStart() { - yield takeLatest(USER_ACTION_TYPES.GOOGLE_SIGN_IN_START, signInWithGoogle) -} - -export function* onEmailSignInStart() { - yield takeLatest(USER_ACTION_TYPES.EMAIL_SIGN_IN_START, signInWithEmail) -} - -export function* onSignUpStart() { - yield takeLatest(USER_ACTION_TYPES.SIGN_UP_START, signUp) -} - -export function* onSignUpSuccess() { - yield takeLatest(USER_ACTION_TYPES.SIGN_UP_SUCCESS, signInAfterSignUp) -} - -export function* onSignOutStart() { - yield takeLatest(USER_ACTION_TYPES.SIGN_OUT_START, signOut) -} - -// user sagas -export function* userSagas() { - yield all([ - call(onCheckUserSession), - call(onGoogleSignInStart), - call(onEmailSignInStart), - call(onSignUpStart), - call(onSignUpSuccess), - call(onSignOutStart) - ]) -} \ No newline at end of file diff --git a/src/store/shared/user/user.saga.ts b/src/store/shared/user/user.saga.ts new file mode 100644 index 0000000..abfee36 --- /dev/null +++ b/src/store/shared/user/user.saga.ts @@ -0,0 +1,248 @@ +import { takeLatest, put, all, call } from "typed-redux-saga/macro"; +import { USER_ACTION_TYPES } from "./user.types"; +import { signInSuccess, signInFailed, + signUpStart, signUpSuccess, signUpFailed, + signOutSuccess, signOutFailed, + EmailSignInStart, + SignUpStart, + SignUpSuccess +} from "./user.action"; + +import { getCurrentUser, + createUserDocumentFromAuth, + signInWithGooglePopup, + signInAuthUserWithEmailAndPassword, + createAuthUserWithEmailAndPassword, + signOutUser, + AdditionalInformation +} from "../../../utils/firebase/firebase.utils" +import { User } from "firebase/auth"; + +// helper functions +export function* getSnapshotFromUserAuth(userAuth: User, additionalDetails?: AdditionalInformation) { + try { + const userSnapshot = yield* call(createUserDocumentFromAuth, userAuth, additionalDetails) + + if (userSnapshot) { + // yield* put(signInSuccess({ uid: userSnapshot.id, ...userSnapshot.data() })) + yield* put(signInSuccess({ ...userSnapshot.data() })) + } + + } catch (error) { + yield* put(signInFailed(error as Error)) + } +} + +export function* isUserAuthenticated() { + try { + const userAuth = yield* call(getCurrentUser) + if (!userAuth) return + yield* call(getSnapshotFromUserAuth, userAuth) + } catch (error) { + yield* put(signInFailed(error as Error)) + } +} + +export function* signInWithGoogle() { + try { + const { user } = yield* call(signInWithGooglePopup) + yield* call(getSnapshotFromUserAuth, user) + } catch (error) { + yield* put(signInFailed(error as Error)) + } +} + +export function* signInWithEmail({ payload: { email, password } }: EmailSignInStart) { + try { + const userCredential = yield* call( + signInAuthUserWithEmailAndPassword, + email, password + ) + + if (userCredential) { + const { user } = userCredential + yield* call(getSnapshotFromUserAuth, user) + } + } catch (error) { + yield* put(signInFailed(error as Error)) + } +} + +export function* signUp({ payload: { email, password, displayName } }: SignUpStart) { + try { + const userCredential = yield* call(createAuthUserWithEmailAndPassword, email, password) + + if (userCredential) { + const { user } = userCredential + yield* put(signUpSuccess(user, { displayName })) + } + + } catch (error) { + yield* put(signUpFailed(error as Error)) + } +} + +export function* signInAfterSignUp({ payload: { user, additionalDetails } }: SignUpSuccess) { + yield* call(getSnapshotFromUserAuth, user, additionalDetails) +} + +export function* signOut() { + try { + yield* call(signOutUser) + yield* put(signOutSuccess()) + } catch (error) { + yield* put(signOutFailed(error as Error)) + } +} + +// callbacks on actions +export function* onCheckUserSession() { + yield* takeLatest(USER_ACTION_TYPES.CHECK_USER_SESSION, isUserAuthenticated) +} + +export function* onGoogleSignInStart() { + yield* takeLatest(USER_ACTION_TYPES.GOOGLE_SIGN_IN_START, signInWithGoogle) +} + +export function* onEmailSignInStart() { + yield* takeLatest(USER_ACTION_TYPES.EMAIL_SIGN_IN_START, signInWithEmail) +} + +export function* onSignUpStart() { + yield* takeLatest(USER_ACTION_TYPES.SIGN_UP_START, signUp) +} + +export function* onSignUpSuccess() { + yield* takeLatest(USER_ACTION_TYPES.SIGN_UP_SUCCESS, signInAfterSignUp) +} + +export function* onSignOutStart() { + yield* takeLatest(USER_ACTION_TYPES.SIGN_OUT_START, signOut) +} + +// user sagas +export function* userSagas() { + yield* all([ + call(onCheckUserSession), + call(onGoogleSignInStart), + call(onEmailSignInStart), + call(onSignUpStart), + call(onSignUpSuccess), + call(onSignOutStart) + ]) +} + +// import { takeLatest, put, all, call } from "redux-saga/effects"; +// import { USER_ACTION_TYPES } from "./user.types"; +// import { signInSuccess, signInFailed, +// signUpStart, signUpSuccess, signUpFailed, +// signOutSuccess, signOutFailed +// } from "./user.action"; + +// import { getCurrentUser, +// createUserDocumentFromAuth, +// signInWithGooglePopup, +// signInAuthUserWithEmailAndPassword, +// createAuthUserWithEmailAndPassword, +// signOutUser +// } from "../../../utils/firebase/firebase.utils" + +// // helper functions +// export function* getSnapshotFromUserAuth(userAuth, additionalDetails) { +// try { +// const userSnapshot = yield call(createUserDocumentFromAuth, userAuth, additionalDetails) +// yield put(signInSuccess({ uid: userSnapshot.id, ...userSnapshot.data() })) +// } catch (error) { +// yield put(signInFailed(error)) +// } +// } + +// export function* isUserAuthenticated() { +// try { +// const userAuth = yield call(getCurrentUser) +// if (!userAuth) return +// yield call(getSnapshotFromUserAuth, userAuth) +// } catch (error) { +// yield put(signInFailed(error)) +// } +// } + +// export function* signInWithGoogle() { +// try { +// const { user } = yield call(signInWithGooglePopup) +// yield call(getSnapshotFromUserAuth, user) +// } catch (error) { +// yield put(signInFailed(error)) +// } +// } + +// export function* signInWithEmail({ payload: { email, password } }) { +// try { +// const { user } = yield call( +// signInAuthUserWithEmailAndPassword, +// email, password +// ) +// yield call(getSnapshotFromUserAuth, user) +// } catch (error) { +// yield put(signInFailed(error)) +// } +// } + +// export function* signUp({ payload: { email, password, displayName } }) { +// try { +// const { user } = yield call(createAuthUserWithEmailAndPassword, email, password) +// yield put(signUpSuccess(user, { displayName })) +// } catch (error) { +// yield put(signUpFailed(error)) +// } +// } + +// export function* signInAfterSignUp({ payload: { user, additionalDetails } }) { +// yield call(getSnapshotFromUserAuth, user, additionalDetails) +// } + +// export function* signOut() { +// try { +// yield call(signOutUser) +// yield put(signOutSuccess()) +// } catch (error) { +// yield put(signOutFailed(error)) +// } +// } + +// // callbacks on actions +// export function* onCheckUserSession() { +// yield takeLatest(USER_ACTION_TYPES.CHECK_USER_SESSION, isUserAuthenticated) +// } + +// export function* onGoogleSignInStart() { +// yield takeLatest(USER_ACTION_TYPES.GOOGLE_SIGN_IN_START, signInWithGoogle) +// } + +// export function* onEmailSignInStart() { +// yield takeLatest(USER_ACTION_TYPES.EMAIL_SIGN_IN_START, signInWithEmail) +// } + +// export function* onSignUpStart() { +// yield takeLatest(USER_ACTION_TYPES.SIGN_UP_START, signUp) +// } + +// export function* onSignUpSuccess() { +// yield takeLatest(USER_ACTION_TYPES.SIGN_UP_SUCCESS, signInAfterSignUp) +// } + +// export function* onSignOutStart() { +// yield takeLatest(USER_ACTION_TYPES.SIGN_OUT_START, signOut) +// } + +// // user sagas +// export function* userSagas() { +// yield all([ +// call(onCheckUserSession), +// call(onGoogleSignInStart), +// call(onEmailSignInStart), +// call(onSignUpStart), +// call(onSignUpSuccess), +// call(onSignOutStart) +// ]) +// } \ No newline at end of file diff --git a/src/store/shared/user/user.selector.js b/src/store/shared/user/user.selector.js deleted file mode 100644 index 4249515..0000000 --- a/src/store/shared/user/user.selector.js +++ /dev/null @@ -1 +0,0 @@ -export const selectCurrentUser = (state) => state.user.currentUser \ No newline at end of file diff --git a/src/store/shared/user/user.selector.ts b/src/store/shared/user/user.selector.ts new file mode 100644 index 0000000..834bf68 --- /dev/null +++ b/src/store/shared/user/user.selector.ts @@ -0,0 +1,12 @@ +import { RootState } from "../../store" +import { UserState } from "./user.reducer" +import { createSelector } from "reselect" + +export const selectUserReducer = (state: RootState): UserState => state.user + +export const selectCurrentUser = createSelector( + selectUserReducer, + (user) => user.currentUser +) + +// export const selectCurrentUser = (state) => state.user.currentUser \ No newline at end of file diff --git a/src/store/shared/user/user.types.js b/src/store/shared/user/user.types.js deleted file mode 100644 index bd0dafa..0000000 --- a/src/store/shared/user/user.types.js +++ /dev/null @@ -1,17 +0,0 @@ -export const USER_ACTION_TYPES = { - SET_CURRENT_USER: "user/SET_CURRENT_USER", - CHECK_USER_SESSION: "user/CHECK_USER_SESSION", - - GOOGLE_SIGN_IN_START: "user/GOOGLE_SIGN_IN_START", - EMAIL_SIGN_IN_START: "user/EMAIL_SIGN_IN_START", - SIGN_IN_SUCCESS: "user/SIGN_IN_SUCCESS", - SIGN_IN_FAILED: "user/SIGN_IN_FAILED", - - SIGN_UP_START: "user/SIGN_UP_START", - SIGN_UP_SUCCESS: "user/SIGN_UP_SUCCESS", - SIGN_UP_FAILED: "user/SIGN_UP_FAILED", - - SIGN_OUT_START: "user/SIGN_OUT_START", - SIGN_OUT_SUCCESS: "user/SIGN_OUT_SUCCESS", - SIGN_OUT_FAILED: "user/SIGN_OUT_FAILED", -} \ No newline at end of file diff --git a/src/store/shared/user/user.types.ts b/src/store/shared/user/user.types.ts new file mode 100644 index 0000000..283f430 --- /dev/null +++ b/src/store/shared/user/user.types.ts @@ -0,0 +1,35 @@ +export enum USER_ACTION_TYPES { + SET_CURRENT_USER = "user/SET_CURRENT_USER", + CHECK_USER_SESSION = "user/CHECK_USER_SESSION", + + GOOGLE_SIGN_IN_START = "user/GOOGLE_SIGN_IN_START", + EMAIL_SIGN_IN_START = "user/EMAIL_SIGN_IN_START", + SIGN_IN_SUCCESS = "user/SIGN_IN_SUCCESS", + SIGN_IN_FAILED = "user/SIGN_IN_FAILED", + + SIGN_UP_START = "user/SIGN_UP_START", + SIGN_UP_SUCCESS = "user/SIGN_UP_SUCCESS", + SIGN_UP_FAILED = "user/SIGN_UP_FAILED", + + SIGN_OUT_START = "user/SIGN_OUT_START", + SIGN_OUT_SUCCESS = "user/SIGN_OUT_SUCCESS", + SIGN_OUT_FAILED = "user/SIGN_OUT_FAILED", +} + +// export const USER_ACTION_TYPES = { +// SET_CURRENT_USER: "user/SET_CURRENT_USER", +// CHECK_USER_SESSION: "user/CHECK_USER_SESSION", + +// GOOGLE_SIGN_IN_START: "user/GOOGLE_SIGN_IN_START", +// EMAIL_SIGN_IN_START: "user/EMAIL_SIGN_IN_START", +// SIGN_IN_SUCCESS: "user/SIGN_IN_SUCCESS", +// SIGN_IN_FAILED: "user/SIGN_IN_FAILED", + +// SIGN_UP_START: "user/SIGN_UP_START", +// SIGN_UP_SUCCESS: "user/SIGN_UP_SUCCESS", +// SIGN_UP_FAILED: "user/SIGN_UP_FAILED", + +// SIGN_OUT_START: "user/SIGN_OUT_START", +// SIGN_OUT_SUCCESS: "user/SIGN_OUT_SUCCESS", +// SIGN_OUT_FAILED: "user/SIGN_OUT_FAILED", +// } \ No newline at end of file diff --git a/src/store/signed-out/nutrition-tracker/nutrition-tracker.action.js b/src/store/signed-out/nutrition-tracker/nutrition-tracker.action.ts similarity index 50% rename from src/store/signed-out/nutrition-tracker/nutrition-tracker.action.js rename to src/store/signed-out/nutrition-tracker/nutrition-tracker.action.ts index 1ba173a..40b0f8b 100644 --- a/src/store/signed-out/nutrition-tracker/nutrition-tracker.action.js +++ b/src/store/signed-out/nutrition-tracker/nutrition-tracker.action.ts @@ -1,18 +1,47 @@ import { validatePredictionInfo, validateAddDayTracked, validateUpdateDayTracked, validateFilterNutritionTrackedDays, validateRemoveNutritionTrackedDay } from "../../../utils/validations/nutrition-tracker.validations"; -import { calculateSummary } from "../../../utils/calculations/nutrition-tracker.calculations"; import { DEFAULT_MICRONUTRIENT } from "../../../utils/constants/nutrition-tracker.constants"; -import { createAction } from "../../../utils/reducer/reducer.utils"; -import { NUTRITION_TRACKER_ACTION_TYPES } from "./nutrition-tracker.types"; +import { createAction, ActionWithPayload, withMatcher } from "../../../utils/reducer/reducer.utils"; +import { DayTrackedSearchResult, FilterConditions, FormInputMicronutrient, Micronutrient, NUTRITION_TRACKER_ACTION_TYPES, NutritionTrackedDay, NutritionTrackedDaysSummary, NutritionTrackedDaysView, PredictionNutritionInfo, ScheduledNutritionTrackedDaysView } from "./nutrition-tracker.types"; + +export type AddDayTracked = ActionWithPayload +export type UpdateDayTracked = ActionWithPayload +export type RemoveDayTracked = ActionWithPayload +export type AddDayTrackedFromPrediction = ActionWithPayload + +export type GetDayTracked = ActionWithPayload + +export type AddFormInputMicronutrients = ActionWithPayload +export type UpdateFormInputMicronutrients = ActionWithPayload +export type DeleteFormInputMicronutrients = ActionWithPayload +export type SetFormInputMicronutrients = ActionWithPayload + +export type FilterDayTracked = ActionWithPayload +export type ClearDayTrackedFilter = ActionWithPayload + +export type SetNutritionTrackedDaysView = ActionWithPayload +export type SetNutritionTrackedDaysSummary = ActionWithPayload + +export type SelectScheduledNutritionTrackedDay = ActionWithPayload +export type SetScheduledNutritionTrackedDaysView = ActionWithPayload // TODO: sort the records by date // helper functions -const addDayTrackedFromPredictionHelper = (nutritionTrackedDays, predictionNutritionInfo) => { +const addDayTrackedFromPredictionHelper = (nutritionTrackedDays: NutritionTrackedDay[], predictionNutritionInfo: PredictionNutritionInfo): NutritionTrackedDay[] => { if (validatePredictionInfo(nutritionTrackedDays, predictionNutritionInfo)) return nutritionTrackedDays + let micronutrients: Micronutrient[] = [] + predictionNutritionInfo.micronutrients.map((micronutrient) => { + micronutrients.push({ + name: String(micronutrient.name), + amount: Number(micronutrient.amount), + unit: String(micronutrient.unit) + }) + }) + return [ ...nutritionTrackedDays, { @@ -23,19 +52,28 @@ const addDayTrackedFromPredictionHelper = (nutritionTrackedDays, predictionNutri protein: Number(predictionNutritionInfo.macronutrients.protein), fat: Number(predictionNutritionInfo.macronutrients.fat), }, - micronutrients: predictionNutritionInfo.micronutrients + micronutrients: micronutrients } ] } -const addMicronutrientsToTrackedDayInfoHelper = (formInputMicronutrients, trackedDayInfo) => { +const addMicronutrientsToTrackedDayInfoHelper = (formInputMicronutrients: FormInputMicronutrient[], trackedDayInfo: NutritionTrackedDay): NutritionTrackedDay => { + let micronutrients: Micronutrient[] = [] + formInputMicronutrients.map((micronutrient) => { + micronutrients.push({ + name: String(micronutrient.name), + amount: Number(micronutrient.amount), + unit: String(micronutrient.unit) + }) + }) + return { ...trackedDayInfo, - micronutrients: formInputMicronutrients + micronutrients: micronutrients } }; -const addDayTrackedHelper = (nutritionTrackedDays, formInputMicronutrients, trackedDayInfo) => { +const addDayTrackedHelper = (nutritionTrackedDays: NutritionTrackedDay[], formInputMicronutrients: FormInputMicronutrient[], trackedDayInfo: NutritionTrackedDay): NutritionTrackedDay[] => { // add formInputMicronutrients to trackedDayInfo const trackedDayWithMicronutrients = addMicronutrientsToTrackedDayInfoHelper(formInputMicronutrients, trackedDayInfo); @@ -58,7 +96,8 @@ const addDayTrackedHelper = (nutritionTrackedDays, formInputMicronutrients, trac ]; }; -const updateDayTrackedHelper = (nutritionTrackedDays, formInputMicronutrients, updatedTrackedDayInfo) => { +const updateDayTrackedHelper = (nutritionTrackedDays: NutritionTrackedDay[], formInputMicronutrients: FormInputMicronutrient[], + updatedTrackedDayInfo: NutritionTrackedDay): NutritionTrackedDay[] => { // add formInputMicronutrients to trackedDayInfo const trackedDayWithMicronutrients = addMicronutrientsToTrackedDayInfoHelper(formInputMicronutrients, updatedTrackedDayInfo); @@ -86,7 +125,7 @@ const updateDayTrackedHelper = (nutritionTrackedDays, formInputMicronutrients, u return updatedNutritionTrackedDays; }; -const getDayTrackedHelper = (nutritionTrackedDays, trackedDay) => { +const getDayTrackedHelper = (nutritionTrackedDays: NutritionTrackedDay[], trackedDay: NutritionTrackedDay): DayTrackedSearchResult => { // return trackedDay info where nutritionTrackedDays's dateTracked is equal to trackedDay.dateTracked const trackedDayInfo = nutritionTrackedDays.find((nutritionTrackedDay) => { @@ -96,20 +135,21 @@ const getDayTrackedHelper = (nutritionTrackedDays, trackedDay) => { return trackedDayInfo; }; -const addFormInputMicronutrientsHelper = (formInputMicronutrients) => { +const addFormInputMicronutrientsHelper = (formInputMicronutrients: FormInputMicronutrient[]): FormInputMicronutrient[] => { // add default micronutrient to formInputMicronutrients return [ ...formInputMicronutrients, DEFAULT_MICRONUTRIENT ]; }; -const updateFormInputMicronutrientsHelper = (formInputMicronutrients, micronutrient, micronutrientIndex) => { +const updateFormInputMicronutrientsHelper = (formInputMicronutrients: FormInputMicronutrient[], + micronutrient: FormInputMicronutrient, micronutrientIndex: number): FormInputMicronutrient[] => { // update formInputMicronutrients on micronutrientIndex with micronutrient const updatedFormInputMicronutrients = formInputMicronutrients.map((micront, index) => { if (index === micronutrientIndex) { return { name: String(micronutrient.name), - amount: Number(micronutrient.amount), + amount: String(micronutrient.amount), unit: String(micronutrient.unit), }; } @@ -117,10 +157,10 @@ const updateFormInputMicronutrientsHelper = (formInputMicronutrients, micronutri return micront; }); - return updatedFormInputMicronutrients;; + return updatedFormInputMicronutrients; }; -const deleteFormInputMicronutrientsHelper = (formInputMicronutrients, micronutrientIndex) => { +const deleteFormInputMicronutrientsHelper = (formInputMicronutrients: FormInputMicronutrient[], micronutrientIndex: number): FormInputMicronutrient[] => { // remove micronutrient from formInputMicronutrients on index with micronutrientIndex const deleteMicronutrients = [ ...formInputMicronutrients ]; @@ -129,11 +169,11 @@ const deleteFormInputMicronutrientsHelper = (formInputMicronutrients, micronutri return deleteMicronutrients; }; -export const filterDayTrackedHelper = (nutritionTrackedDays, filterConditions) => { - let filteredNutritionTrackedDays = [] +export const filterDayTrackedHelper = (nutritionTrackedDays: NutritionTrackedDay[], filterConditions: FilterConditions): NutritionTrackedDay[] => { + let filteredNutritionTrackedDays: NutritionTrackedDay[] = [] nutritionTrackedDays.map((trackedDay) => { - if (filterConditions.filterStartDate === "" || (filterConditions.filterStartDate <= trackedDay.dateTracked)) { - if (filterConditions.filterEndDate === "" || (trackedDay.dateTracked <= filterConditions.filterEndDate)) { + if ((filterConditions.filterStartDate && filterConditions.filterStartDate !== "") || (filterConditions.filterStartDate! <= trackedDay.dateTracked)) { + if ((filterConditions.filterEndDate && filterConditions.filterEndDate === "") || (trackedDay.dateTracked <= filterConditions.filterEndDate!)) { filteredNutritionTrackedDays.push(trackedDay) } } @@ -142,13 +182,13 @@ export const filterDayTrackedHelper = (nutritionTrackedDays, filterConditions) = return filteredNutritionTrackedDays } -const removeDayTrackedHelper = (nutritionTrackedDays, trackedDay) => { +const removeDayTrackedHelper = (nutritionTrackedDays: NutritionTrackedDay[], trackedDay: string | Date): NutritionTrackedDay[] => { if (validateRemoveNutritionTrackedDay(trackedDay)) return nutritionTrackedDays return nutritionTrackedDays.filter(nutritionTrackedDay => nutritionTrackedDay.dateTracked !== trackedDay) } -export const selectScheduledNutritionTrackedDayHelper = (nutritionTrackedDays, trackedDay) => { +export const selectScheduledNutritionTrackedDayHelper = (nutritionTrackedDays: NutritionTrackedDay[], trackedDay: string | Date): NutritionTrackedDay | null => { const filteredNutritionTrackedDay = nutritionTrackedDays.find((nutritionTrackedDay) => { return nutritionTrackedDay.dateTracked === trackedDay }) @@ -160,77 +200,77 @@ export const selectScheduledNutritionTrackedDayHelper = (nutritionTrackedDays, t // actions -export const addDayTracked = (nutritionTrackedDays, formInputMicronutrients, trackedDayInfo) => { +export const addDayTracked = withMatcher((nutritionTrackedDays: NutritionTrackedDay[], formInputMicronutrients: FormInputMicronutrient[], trackedDayInfo: NutritionTrackedDay): AddDayTracked => { const newNutritionTrackedDays = addDayTrackedHelper(nutritionTrackedDays, formInputMicronutrients, trackedDayInfo) // setFormInputMicronutrients([]); return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS, newNutritionTrackedDays) -}; +}) -export const updateDayTracked = (nutritionTrackedDays, formInputMicronutrients, updatedTrackedDayInfo) => { +export const updateDayTracked = withMatcher((nutritionTrackedDays: NutritionTrackedDay[], formInputMicronutrients: FormInputMicronutrient[], updatedTrackedDayInfo: NutritionTrackedDay): UpdateDayTracked => { const newNutritionTrackedDays = updateDayTrackedHelper(nutritionTrackedDays, formInputMicronutrients, updatedTrackedDayInfo) // setFormInputMicronutrients([]); return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS, newNutritionTrackedDays) -}; +}) -export const getDayTracked = (nutritionTrackedDays, trackedDay) => { +export const getDayTracked = withMatcher((nutritionTrackedDays: NutritionTrackedDay[], trackedDay: NutritionTrackedDay): GetDayTracked => { const newDayTrackedSearchResult = getDayTrackedHelper(nutritionTrackedDays, trackedDay) return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_DAY_TRACKED_SEARCH_RESULT, newDayTrackedSearchResult) -}; +}) -export const addFormInputMicronutrients = (formInputMicronutrients) => { +export const addFormInputMicronutrients = withMatcher((formInputMicronutrients: FormInputMicronutrient[]): AddFormInputMicronutrients => { const newFormInputMicronutrients = addFormInputMicronutrientsHelper(formInputMicronutrients) return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_FORM_INPUT_MICRONUTRIENTS, newFormInputMicronutrients) -}; +}) -export const updateFormInputMicronutrients = (formInputMicronutrients, micronutrient, micronutrientIndex) => { +export const updateFormInputMicronutrients = withMatcher((formInputMicronutrients: FormInputMicronutrient[], micronutrient: FormInputMicronutrient, micronutrientIndex: number): UpdateFormInputMicronutrients => { const newFormInputMicronutrients = updateFormInputMicronutrientsHelper(formInputMicronutrients, micronutrient, micronutrientIndex) return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_FORM_INPUT_MICRONUTRIENTS, newFormInputMicronutrients) -}; +}) -export const deleteFormInputMicronutrients = (formInputMicronutrients, micronutrientIndex) => { +export const deleteFormInputMicronutrients = withMatcher((formInputMicronutrients: FormInputMicronutrient[], micronutrientIndex: number): DeleteFormInputMicronutrients => { const newFormInputMicronutrients = deleteFormInputMicronutrientsHelper(formInputMicronutrients, micronutrientIndex) return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_FORM_INPUT_MICRONUTRIENTS, newFormInputMicronutrients) -}; +}) -export const filterDayTracked = (filterConditions) => { +export const filterDayTracked = withMatcher((filterConditions: FilterConditions): any => { if (validateFilterNutritionTrackedDays(filterConditions)) { return } else { return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_FILTER_CONDITIONS, filterConditions) } -} +}) -export const removeDayTracked = (nutritionTrackedDays, trackedDay) => { +export const removeDayTracked = withMatcher((nutritionTrackedDays: NutritionTrackedDay[], trackedDay: string | Date): RemoveDayTracked => { const newNutritionTrackedDays = removeDayTrackedHelper(nutritionTrackedDays, trackedDay) return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS, newNutritionTrackedDays) -} +}) -export const clearDayTrackedFilter = () => { +export const clearDayTrackedFilter = withMatcher((): ClearDayTrackedFilter => { return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_FILTER_CONDITIONS, null) -} +}) -export const setFormInputMicronutrients = (formInputMicronutrients) => { +export const setFormInputMicronutrients = withMatcher((formInputMicronutrients: FormInputMicronutrient[]): SetFormInputMicronutrients => { return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_FORM_INPUT_MICRONUTRIENTS, formInputMicronutrients) -} +}) -export const setNutritionTrackedDaysView = (nutritionTrackedDaysView) => { +export const setNutritionTrackedDaysView = withMatcher((nutritionTrackedDaysView: NutritionTrackedDaysView): SetNutritionTrackedDaysView => { return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS_VIEW, nutritionTrackedDaysView) -} +}) -export const setNutritionTrackedDaysSummary = (nutritionTrackedDaysSummary) => { +export const setNutritionTrackedDaysSummary = withMatcher((nutritionTrackedDaysSummary: NutritionTrackedDaysSummary): SetNutritionTrackedDaysSummary => { return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS_SUMMARY, nutritionTrackedDaysSummary) -} +}) -export const addDayTrackedFromPrediction = (nutritionTrackedDays, predictionNutritionInfo) => { +export const addDayTrackedFromPrediction = withMatcher((nutritionTrackedDays: NutritionTrackedDay[], predictionNutritionInfo: PredictionNutritionInfo): AddDayTrackedFromPrediction => { const newNutritionTrackedDays = addDayTrackedFromPredictionHelper(nutritionTrackedDays, predictionNutritionInfo) return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS, newNutritionTrackedDays) -} +}) -export const selectScheduledNutritionTrackedDay = (dayTracked) => { +export const selectScheduledNutritionTrackedDay = withMatcher((dayTracked: string | Date): SelectScheduledNutritionTrackedDay => { return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_SELECTED_NUTRITION_TRACKED_DAY, dayTracked) -} +}) -export const setScheduledNutritionTrackedDaysView = (scheduledNutritionTrackedDaysView) => { +export const setScheduledNutritionTrackedDaysView = withMatcher((scheduledNutritionTrackedDaysView: ScheduledNutritionTrackedDaysView): SetScheduledNutritionTrackedDaysView => { return createAction(NUTRITION_TRACKER_ACTION_TYPES.SET_SCHEDULED_NUTRITION_TRACKED_DAYS_VIEW, scheduledNutritionTrackedDaysView) -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.js b/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.js deleted file mode 100644 index ff00745..0000000 --- a/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.js +++ /dev/null @@ -1,63 +0,0 @@ -import { NUTRITION_TRACKER_ACTION_TYPES } from "./nutrition-tracker.types"; - -export const NUTRITION_TRACKER_INITIAL_STATE = { - nutritionTrackedDays: [], - formInputMicronutrients: [], - filterConditions: null, - - selectedNutritionTrackedDay: null, - scheduledNutritionTrackedDaysView: null, - - nutritionTrackedDaysView: [], - dayTrackedSearchResult: undefined, - nutritionTrackedDaysSummary: {} -} - -export const nutritionTrackerReducer = (state=NUTRITION_TRACKER_INITIAL_STATE, action={}) => { - const { type, payload } = action - - switch(type) { - case NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS: - return { - ...state, - nutritionTrackedDays: payload - } - case NUTRITION_TRACKER_ACTION_TYPES.SET_FORM_INPUT_MICRONUTRIENTS: - return { - ...state, - formInputMicronutrients: payload - } - case NUTRITION_TRACKER_ACTION_TYPES.SET_FILTER_CONDITIONS: - return { - ...state, - filterConditions: payload - } - case NUTRITION_TRACKER_ACTION_TYPES.SET_SELECTED_NUTRITION_TRACKED_DAY: - return { - ...state, - selectedNutritionTrackedDay: payload - } - case NUTRITION_TRACKER_ACTION_TYPES.SET_SCHEDULED_NUTRITION_TRACKED_DAYS_VIEW: - return { - ...state, - scheduledNutritionTrackedDaysView: payload - } - case NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS_VIEW: - return { - ...state, - nutritionTrackedDaysView: payload - } - case NUTRITION_TRACKER_ACTION_TYPES.SET_DAY_TRACKED_SEARCH_RESULT: - return { - ...state, - dayTrackedSearchResult: payload - } - case NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS_SUMMARY: - return { - ...state, - nutritionTrackedDaysSummary: payload - } - default: - return state - } -} \ No newline at end of file diff --git a/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.toolkit.js b/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.toolkit.ts similarity index 90% rename from src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.toolkit.js rename to src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.toolkit.ts index 7720dc9..84081a1 100644 --- a/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.toolkit.js +++ b/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.toolkit.ts @@ -1,6 +1,7 @@ import { createSlice } from "@reduxjs/toolkit"; +import { NutritionTrackerState } from "./nutrition-tracker.reducer" -export const NUTRITION_TRACKER_INITIAL_STATE = { +export const NUTRITION_TRACKER_INITIAL_STATE: NutritionTrackerState = { nutritionTrackedDays: [], formInputMicronutrients: [], filterConditions: null, diff --git a/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.ts b/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.ts new file mode 100644 index 0000000..e89d45b --- /dev/null +++ b/src/store/signed-out/nutrition-tracker/nutrition-tracker.reducer.ts @@ -0,0 +1,147 @@ +import { PayloadAction } from "@reduxjs/toolkit"; +import { DayTrackedSearchResult, FilterConditions, FormInputMicronutrient, + NutritionTrackedDay, NutritionTrackedDaysSummary, NutritionTrackedDaysView, + ScheduledNutritionTrackedDaysView, SelectedNutritionTrackedDay } + from "./nutrition-tracker.types"; +import { addDayTracked, addDayTrackedFromPrediction, addFormInputMicronutrients, clearDayTrackedFilter, + deleteFormInputMicronutrients, filterDayTracked, getDayTracked, removeDayTracked, selectScheduledNutritionTrackedDay, + setFormInputMicronutrients, setNutritionTrackedDaysSummary, setNutritionTrackedDaysView, + setScheduledNutritionTrackedDaysView, updateDayTracked, updateFormInputMicronutrients } from "./nutrition-tracker.action"; + +export type NutritionTrackerState = { + readonly nutritionTrackedDays: NutritionTrackedDay[] | null | undefined; + readonly formInputMicronutrients: FormInputMicronutrient[] | null | undefined; + readonly filterConditions: FilterConditions | null | undefined; + + readonly selectedNutritionTrackedDay: SelectedNutritionTrackedDay | null | undefined; + readonly scheduledNutritionTrackedDaysView: ScheduledNutritionTrackedDaysView | null | undefined; + + readonly nutritionTrackedDaysView: NutritionTrackedDaysView | null | undefined; + readonly dayTrackedSearchResult: DayTrackedSearchResult | null | undefined; + readonly nutritionTrackedDaysSummary: NutritionTrackedDaysSummary | null | undefined; +} + +export const NUTRITION_TRACKER_INITIAL_STATE: NutritionTrackerState = { + nutritionTrackedDays: [], + formInputMicronutrients: [], + filterConditions: null, + + selectedNutritionTrackedDay: null, + scheduledNutritionTrackedDaysView: null, + + nutritionTrackedDaysView: [], + dayTrackedSearchResult: undefined, + nutritionTrackedDaysSummary: {} +} + +export const nutritionTrackerReducer = ( + state = NUTRITION_TRACKER_INITIAL_STATE, + action: PayloadAction +): NutritionTrackerState => { + if (addDayTracked.match(action) || updateDayTracked.match(action) + || removeDayTracked.match(action) || addDayTrackedFromPrediction.match(action)) { + return { + ...state, + nutritionTrackedDays: action.payload + }; + } + + if (addFormInputMicronutrients.match(action) || updateFormInputMicronutrients.match(action) + || deleteFormInputMicronutrients.match(action) || setFormInputMicronutrients.match(action)) { + return { + ...state, + formInputMicronutrients: action.payload + }; + } + + if (filterDayTracked.match(action) || clearDayTrackedFilter.match(action)) { + return { + ...state, + filterConditions: action.payload + }; + } + + if (selectScheduledNutritionTrackedDay.match(action)) { + return { + ...state, + selectedNutritionTrackedDay: action.payload + }; + } + + if (setScheduledNutritionTrackedDaysView.match(action)) { + return { + ...state, + scheduledNutritionTrackedDaysView: action.payload + }; + } + + if (setNutritionTrackedDaysView.match(action)) { + return { + ...state, + nutritionTrackedDaysView: action.payload + }; + } + + if (getDayTracked.match(action)) { + return { + ...state, + dayTrackedSearchResult: action.payload + }; + } + + if (setNutritionTrackedDaysSummary.match(action)) { + return { + ...state, + nutritionTrackedDaysSummary: action.payload + }; + } + + return state; + + // const { type, payload } = action + + // switch(type) { + // case NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS: + // return { + // ...state, + // nutritionTrackedDays: payload + // } + // case NUTRITION_TRACKER_ACTION_TYPES.SET_FORM_INPUT_MICRONUTRIENTS: + // return { + // ...state, + // formInputMicronutrients: payload + // } + // case NUTRITION_TRACKER_ACTION_TYPES.SET_FILTER_CONDITIONS: + // return { + // ...state, + // filterConditions: payload + // } + // case NUTRITION_TRACKER_ACTION_TYPES.SET_SELECTED_NUTRITION_TRACKED_DAY: + // return { + // ...state, + // selectedNutritionTrackedDay: payload + // } + // case NUTRITION_TRACKER_ACTION_TYPES.SET_SCHEDULED_NUTRITION_TRACKED_DAYS_VIEW: + // return { + // ...state, + // scheduledNutritionTrackedDaysView: payload + // } + // case NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS_VIEW: + // return { + // ...state, + // nutritionTrackedDaysView: payload + // } + // case NUTRITION_TRACKER_ACTION_TYPES.SET_DAY_TRACKED_SEARCH_RESULT: + // return { + // ...state, + // dayTrackedSearchResult: payload + // } + // case NUTRITION_TRACKER_ACTION_TYPES.SET_NUTRITION_TRACKED_DAYS_SUMMARY: + // return { + // ...state, + // nutritionTrackedDaysSummary: payload + // } + // default: + // return state + // } +} \ No newline at end of file diff --git a/src/store/signed-out/nutrition-tracker/nutrition-tracker.selector.js b/src/store/signed-out/nutrition-tracker/nutrition-tracker.selector.ts similarity index 86% rename from src/store/signed-out/nutrition-tracker/nutrition-tracker.selector.js rename to src/store/signed-out/nutrition-tracker/nutrition-tracker.selector.ts index cfc9419..fb4e4a5 100644 --- a/src/store/signed-out/nutrition-tracker/nutrition-tracker.selector.js +++ b/src/store/signed-out/nutrition-tracker/nutrition-tracker.selector.ts @@ -1,6 +1,8 @@ import { createSelector } from "reselect" +import { NutritionTrackerState } from "./nutrition-tracker.reducer" +import { RootState } from "../../store" -const selectNutritionTrackerReducer = state => state.nutritionTracker +const selectNutritionTrackerReducer = (state: RootState): NutritionTrackerState => state.nutritionTracker export const selectNutritionTrackedDays = createSelector( [selectNutritionTrackerReducer], diff --git a/src/store/signed-out/nutrition-tracker/nutrition-tracker.types.js b/src/store/signed-out/nutrition-tracker/nutrition-tracker.types.js deleted file mode 100644 index a64732e..0000000 --- a/src/store/signed-out/nutrition-tracker/nutrition-tracker.types.js +++ /dev/null @@ -1,12 +0,0 @@ -export const NUTRITION_TRACKER_ACTION_TYPES = { - SET_NUTRITION_TRACKED_DAYS: "nutrition-tracker/SET_NUTRITION_TRACKED_DAYS", - SET_FORM_INPUT_MICRONUTRIENTS: "nutrition-tracker/SET_FORM_INPUT_MICRONUTRIENTS", - SET_FILTER_CONDITIONS: "nutrition-tracker/SET_FILTER_CONDITIONS", - - SET_SELECTED_NUTRITION_TRACKED_DAY: "nutrition-tracker/SET_SELECTED_NUTRITION_TRACKED_DAY", - SET_SCHEDULED_NUTRITION_TRACKED_DAYS_VIEW: "nutrition-tracker/SET_SCHEDULED_NUTRITION_TRACKED_DAYS_VIEW", - - SET_NUTRITION_TRACKED_DAYS_VIEW: "nutrition-tracker/SET_NUTRITION_TRACKED_DAYS_VIEW", - SET_DAY_TRACKED_SEARCH_RESULT: "nutrition-tracker/SET_DAY_TRACKED_SEARCH_RESULT", - SET_NUTRITION_TRACKED_DAYS_SUMMARY: "nutrition-tracker/SET_NUTRITION_TRACKED_DAYS_SUMMARY" -} \ No newline at end of file diff --git a/src/store/signed-out/nutrition-tracker/nutrition-tracker.types.ts b/src/store/signed-out/nutrition-tracker/nutrition-tracker.types.ts new file mode 100644 index 0000000..682ca2f --- /dev/null +++ b/src/store/signed-out/nutrition-tracker/nutrition-tracker.types.ts @@ -0,0 +1,64 @@ +export enum NUTRITION_TRACKER_ACTION_TYPES { + SET_NUTRITION_TRACKED_DAYS = "nutrition-tracker/SET_NUTRITION_TRACKED_DAYS", + SET_FORM_INPUT_MICRONUTRIENTS = "nutrition-tracker/SET_FORM_INPUT_MICRONUTRIENTS", + SET_FILTER_CONDITIONS = "nutrition-tracker/SET_FILTER_CONDITIONS", + + SET_SELECTED_NUTRITION_TRACKED_DAY = "nutrition-tracker/SET_SELECTED_NUTRITION_TRACKED_DAY", + SET_SCHEDULED_NUTRITION_TRACKED_DAYS_VIEW = "nutrition-tracker/SET_SCHEDULED_NUTRITION_TRACKED_DAYS_VIEW", + + SET_NUTRITION_TRACKED_DAYS_VIEW = "nutrition-tracker/SET_NUTRITION_TRACKED_DAYS_VIEW", + SET_DAY_TRACKED_SEARCH_RESULT = "nutrition-tracker/SET_DAY_TRACKED_SEARCH_RESULT", + SET_NUTRITION_TRACKED_DAYS_SUMMARY = "nutrition-tracker/SET_NUTRITION_TRACKED_DAYS_SUMMARY" +} + +export type NutritionTrackedDay = { + dateTracked: string; + calories: number; + macronutrients: Macronutrient; + micronutrients: Micronutrient[]; +} + +export type Macronutrient = { + carbohydrates: number; + protein: number; + fat: number; +} + +export type Micronutrient = { + name: string; + amount: number; + unit: string; +} + +export type FormInputMicronutrient = { + name: string; + amount: string; + unit: string; +} + +export type SelectedNutritionTrackedDay = string | Date | null; + +export type FilterConditions = { + filterStartDate?: string; + filterEndDate?: string; +} + +export type NutritionTrackedDaysView = NutritionTrackedDay[]; + +export type ScheduledNutritionTrackedDaysView = NutritionTrackedDay + +export type DayTrackedSearchResult = NutritionTrackedDay | undefined; + +export type NutritionTrackedDaysSummary = { + averageDailyCaloriesConsumption?: number; + averageDailyCarbohydratesConsumption?: number; + averageDailyProteinConsumption?: number; + averageDailyFatConsumption?: number; +} + +export type PredictionNutritionInfo = { + dateTracked: string | Date; + calories: number; + macronutrients: Macronutrient; + micronutrients: Micronutrient[]; +} \ No newline at end of file diff --git a/src/store/store.toolkit.js b/src/store/store.toolkit.js deleted file mode 100644 index 8cdfb2e..0000000 --- a/src/store/store.toolkit.js +++ /dev/null @@ -1,14 +0,0 @@ -import { configureStore } from "@reduxjs/toolkit"; -import logger from "redux-logger"; -import rootReducer from "./root-reducer.toolkit" - -const middleWares = [ - process.env.NODE_ENV === "development" && logger -].filter(Boolean) - -export const store = configureStore({ - reducer: rootReducer, - middleware: (getDefaultMiddleware) => getDefaultMiddleware({ - serializableCheck: false - }).concat(middleWares) -}) \ No newline at end of file diff --git a/src/store/store.toolkit.ts b/src/store/store.toolkit.ts new file mode 100644 index 0000000..20f7667 --- /dev/null +++ b/src/store/store.toolkit.ts @@ -0,0 +1,30 @@ +// import { configureStore } from "@reduxjs/toolkit"; +// import logger from "redux-logger"; +// import { rootReducer } from "./root-reducer.toolkit"; + +// const middleWares = [ +// process.env.NODE_ENV === "development" && logger +// ].filter(Boolean) + +// export const store = configureStore({ +// reducer: rootReducer, +// middleware: (getDefaultMiddleware) => getDefaultMiddleware({ +// serializableCheck: false +// }).concat(middleWares) +// }) + + +// import { configureStore } from "@reduxjs/toolkit"; +// import logger from "redux-logger"; +// import rootReducer from "./root-reducer.toolkit" + +// const middleWares = [ +// process.env.NODE_ENV === "development" && logger +// ].filter(Boolean) + +// export const store = configureStore({ +// reducer: rootReducer, +// middleware: (getDefaultMiddleware) => getDefaultMiddleware({ +// serializableCheck: false +// }).concat(middleWares) +// }) \ No newline at end of file diff --git a/src/store/store.js b/src/store/store.ts similarity index 89% rename from src/store/store.js rename to src/store/store.ts index 5be3715..a599ed0 100644 --- a/src/store/store.js +++ b/src/store/store.ts @@ -9,6 +9,14 @@ import createSagaMiddleware from "redux-saga" import { rootSaga } from "./root-saga" +export type RootState = ReturnType + +declare global { + interface Window { + __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose + } +} + // middlewares const sagaMiddleware = createSagaMiddleware() diff --git a/src/utils/reducer/reducer.utils.js b/src/utils/reducer/reducer.utils.js deleted file mode 100644 index bc27483..0000000 --- a/src/utils/reducer/reducer.utils.js +++ /dev/null @@ -1,4 +0,0 @@ -// reducer utils - -// creating reducer action -export const createAction = (type, payload) => ({ type, payload }) \ No newline at end of file diff --git a/src/utils/reducer/reducer.utils.ts b/src/utils/reducer/reducer.utils.ts new file mode 100644 index 0000000..d3ec888 --- /dev/null +++ b/src/utils/reducer/reducer.utils.ts @@ -0,0 +1,39 @@ +import { AnyAction } from "redux" + +type Matchable AnyAction> = AC & { + type: ReturnType['type']; + match(action: AnyAction): action is ReturnType; +} + +export function withMatcher AnyAction & { type: string }>(actionCreator: AC): Matchable; + +export function withMatcher AnyAction & { type: string }>(actionCreator: AC): Matchable; + +export function withMatcher(actionCreator: Function) { + const type = actionCreator().type; + return Object.assign(actionCreator, { + type, + match(action: AnyAction) { + return action.type === type + } + }) +} + +// reducer utils +export type ActionWithPayload = { + type: T; + payload: P; +} + +export type Action = { + type: T; +} + +// creating reducer action +export function createAction(type: T, payload: P): ActionWithPayload; + +export function createAction(type: T, payload: void): Action; + +export function createAction(type: T, payload: P) { + return { type, payload }; +} \ No newline at end of file