Repository: vangelov/calories-in
Branch: master
Commit: 2dd62babb5e8
Files: 340
Total size: 591.2 KB
Directory structure:
gitextract_ov6rt79l/
├── .gitignore
├── .husky/
│ ├── .gitignore
│ └── pre-commit
├── .prettierignore
├── .prettierrc
├── .vscode/
│ └── settings.json
├── LICENSE
├── README.md
├── package.json
├── public/
│ ├── browserconfig.xml
│ ├── index.html
│ ├── robots.txt
│ └── site.webmanifest
├── src/
│ ├── App.tsx
│ ├── diets/
│ │ ├── DietEditor/
│ │ │ ├── DndContextProvider.tsx
│ │ │ ├── Form/
│ │ │ │ ├── About.tsx
│ │ │ │ ├── Controls/
│ │ │ │ │ ├── ExportButton.tsx
│ │ │ │ │ ├── MenuOrDrawer.tsx
│ │ │ │ │ ├── Name.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Footer.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── useDietFormEvents.ts
│ │ │ │ └── useVariantFormActions.ts
│ │ │ └── index.tsx
│ │ ├── PdfDietEditor.tsx
│ │ ├── dietForm.ts
│ │ ├── index.ts
│ │ ├── persistence/
│ │ │ ├── ExportModal/
│ │ │ │ ├── Content/
│ │ │ │ │ ├── Exporter/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── usePdfExport.ts
│ │ │ │ │ │ └── worker/
│ │ │ │ │ │ ├── custom.d.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ └── worker.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── canExportDietForm.ts
│ │ │ ├── hasMissingFoods.ts
│ │ │ ├── index.ts
│ │ │ ├── loadLastOrDefaultDietForm.ts
│ │ │ ├── parseDietForm.ts
│ │ │ ├── useDietImportErrors.tsx
│ │ │ └── useImportDietForm.ts
│ │ ├── types.ts
│ │ ├── useDietFormStore.ts
│ │ ├── useGetDietFormStatsTree.ts
│ │ └── useScrollManager.ts
│ ├── dom/
│ │ ├── animateScrollLeft.ts
│ │ ├── index.ts
│ │ ├── isElementInViewport.ts
│ │ ├── useGetRefForId.ts
│ │ └── useScrollTo.ts
│ ├── foods/
│ │ ├── FoodInfo.tsx
│ │ ├── FoodModal/
│ │ │ ├── Content/
│ │ │ │ ├── DeleteConfirmationModal.tsx
│ │ │ │ ├── FoodFormProvider.tsx
│ │ │ │ ├── Form/
│ │ │ │ │ ├── Footer.tsx
│ │ │ │ │ ├── Header.tsx
│ │ │ │ │ ├── Tabs/
│ │ │ │ │ │ ├── NutritionFactsFormFields.tsx
│ │ │ │ │ │ ├── UrlField.tsx
│ │ │ │ │ │ ├── VolumeFormFields.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── useSubmitFoodForm.ts
│ │ │ │ │ └── useTabs.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── useDeleteFood.ts
│ │ │ └── index.tsx
│ │ ├── FoodsDrawer/
│ │ │ ├── Content/
│ │ │ │ ├── Header.tsx
│ │ │ │ ├── MenuButtons.tsx
│ │ │ │ ├── SelectedFoodsList/
│ │ │ │ │ ├── SelectedFoodItem.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── useFoodEvents.ts
│ │ │ └── index.tsx
│ │ ├── FoodsList/
│ │ │ ├── VirtualizedList/
│ │ │ │ ├── FoodItem/
│ │ │ │ │ ├── AnimateAppear.tsx
│ │ │ │ │ ├── DisappearingBox.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── FoodItemRenderer.tsx
│ │ │ │ ├── Inner.tsx
│ │ │ │ └── index.tsx
│ │ │ └── index.tsx
│ │ ├── builtIn/
│ │ │ ├── bakedProducts.json
│ │ │ ├── beef.json
│ │ │ ├── beverages.json
│ │ │ ├── dairyAndEggs.json
│ │ │ ├── fatsAndOils.json
│ │ │ ├── finfishAndShellFish.json
│ │ │ ├── fruitsAndJuices.json
│ │ │ ├── grainsAndPasta.json
│ │ │ ├── index.ts
│ │ │ ├── legumesAndLegumeProducts.json
│ │ │ ├── nutAndSeedProducts.json
│ │ │ ├── pork.json
│ │ │ ├── poultry.json
│ │ │ ├── saucesAndSoups.json
│ │ │ ├── spicesAndHerbs.json
│ │ │ ├── sweetsAndSnacks.json
│ │ │ └── vegetables.json
│ │ ├── foodForm.ts
│ │ ├── foodVolumeForm.ts
│ │ ├── index.ts
│ │ ├── persistence/
│ │ │ ├── FoodsListModal/
│ │ │ │ ├── Content.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── MissingFoodsModal.tsx
│ │ │ ├── index.ts
│ │ │ ├── loadFoods.ts
│ │ │ └── useImportFoods.ts
│ │ ├── types.ts
│ │ └── useFoodsStore.ts
│ ├── foods-categories/
│ │ ├── FoodCategoriesSelect.tsx
│ │ ├── categories.json
│ │ ├── index.ts
│ │ └── types.ts
│ ├── foods-filters/
│ │ ├── FoodsFilterPopoverOrModal/
│ │ │ ├── Content.tsx
│ │ │ ├── Footer.tsx
│ │ │ ├── Modal.tsx
│ │ │ ├── Popover.tsx
│ │ │ ├── Trigger.tsx
│ │ │ └── index.tsx
│ │ ├── foodsFilter.ts
│ │ ├── index.ts
│ │ ├── persistence/
│ │ │ ├── index.ts
│ │ │ └── loadFoodsFilter.ts
│ │ ├── useFilterFoods.ts
│ │ └── useFoodsFilterStore.ts
│ ├── form/
│ │ ├── duplicate.ts
│ │ ├── index.ts
│ │ ├── names.ts
│ │ ├── types.ts
│ │ ├── useFormError.ts
│ │ └── useSelectInputText.ts
│ ├── general/
│ │ ├── Badge.tsx
│ │ ├── ContextMenuFlex.tsx
│ │ ├── HFadeScroll/
│ │ │ ├── FadeBox.tsx
│ │ │ ├── ScrollContainer.tsx
│ │ │ └── index.tsx
│ │ ├── Loader.tsx
│ │ ├── Menu.tsx
│ │ ├── MenuOrDrawer/
│ │ │ ├── Drawer/
│ │ │ │ ├── getDrawerButtons.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── Menu/
│ │ │ │ ├── getMenuItems.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── MenuOrDrawerItem.tsx
│ │ │ ├── MenuOrDrawerSeparator.tsx
│ │ │ ├── Trigger.tsx
│ │ │ └── index.tsx
│ │ ├── ResponsiveButton.tsx
│ │ ├── ResponsiveIconButton.tsx
│ │ ├── RightAligned.tsx
│ │ ├── ScreenSizeProvider/
│ │ │ ├── context.ts
│ │ │ └── index.tsx
│ │ ├── Tooltip.tsx
│ │ ├── TooltipCommandLabel.tsx
│ │ ├── deepCopy.ts
│ │ ├── getCtrlKeyName.ts
│ │ ├── index.ts
│ │ ├── minDelay.ts
│ │ ├── stores.tsx
│ │ ├── useElementHeight.ts
│ │ ├── useOneTimeCheckStore.ts
│ │ ├── useRunIfNotUnmounted.ts
│ │ ├── useSameOrPreviousValue.ts
│ │ └── useSelection.ts
│ ├── icons/
│ │ ├── CalendarPlus.tsx
│ │ └── index.ts
│ ├── index.tsx
│ ├── ingredients/
│ │ ├── IngredientsList/
│ │ │ ├── EmptyList.tsx
│ │ │ ├── IngredientItem/
│ │ │ │ ├── MenuOrDrawer.tsx
│ │ │ │ ├── MissingStatsLayout.tsx
│ │ │ │ ├── Notes.tsx
│ │ │ │ ├── PresenceAnimation.tsx
│ │ │ │ ├── StatsLayout.tsx
│ │ │ │ ├── getMenuOrDrawerItems.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── useIngredientsEvents.ts
│ │ │ │ └── useNotesEvents.tsx
│ │ │ └── index.tsx
│ │ ├── PdfIngredientsList/
│ │ │ ├── PdfIngredientItem/
│ │ │ │ ├── FoodName.tsx
│ │ │ │ └── index.tsx
│ │ │ └── index.tsx
│ │ ├── getIngredient.ts
│ │ ├── index.ts
│ │ ├── ingredientForm.ts
│ │ ├── types.ts
│ │ ├── useGetIngredientFormStatsTree.ts
│ │ └── useIngredientsFormsActions.ts
│ ├── layout/
│ │ ├── MainLayout.tsx
│ │ ├── Page/
│ │ │ ├── ElementContainer.tsx
│ │ │ ├── PageBody.tsx
│ │ │ ├── PageFooter.tsx
│ │ │ ├── PageHeader.tsx
│ │ │ └── index.tsx
│ │ ├── RightAligned.tsx
│ │ ├── index.tsx
│ │ └── useHasSideNavigation.ts
│ ├── meals/
│ │ ├── MealsList/
│ │ │ ├── EmptyList.tsx
│ │ │ ├── MealItem/
│ │ │ │ ├── Header/
│ │ │ │ │ ├── MenuOrDrawer.tsx
│ │ │ │ │ ├── Name.tsx
│ │ │ │ │ ├── getMenuOrDrawerItems.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Notes.tsx
│ │ │ │ ├── PresenceAnimation.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── useGetAndUpdateStats.ts
│ │ │ │ └── useMealFormEvents.ts
│ │ │ ├── MealsControls.tsx
│ │ │ ├── index.tsx
│ │ │ └── useScrollToAndFocusMeal.ts
│ │ ├── PdfMealsList/
│ │ │ ├── Notes.tsx
│ │ │ ├── PdfMealItem.tsx
│ │ │ └── index.tsx
│ │ ├── index.ts
│ │ ├── mealForm.ts
│ │ ├── types.ts
│ │ ├── useGetMealFormStatsTree.ts
│ │ └── useMealsFormsActions.ts
│ ├── notes/
│ │ ├── EditNotesModal/
│ │ │ ├── Content/
│ │ │ │ ├── Form/
│ │ │ │ │ ├── Header.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NotesFormProvider.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ └── notesForm.ts
│ │ │ └── index.tsx
│ │ ├── index.ts
│ │ └── notesForm.ts
│ ├── persistence/
│ │ ├── DownloadButton.tsx
│ │ ├── file.ts
│ │ ├── fixWhiteSpace.tsx
│ │ ├── getUntitledFileName.ts
│ │ ├── index.ts
│ │ ├── useBlobUrl.ts
│ │ ├── useImportFileError.ts
│ │ └── useSaveValue.ts
│ ├── portions/
│ │ ├── PortionsMenuOrDrawer/
│ │ │ ├── Drawer/
│ │ │ │ ├── PortionItem.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── Menu.tsx
│ │ │ ├── Trigger.tsx
│ │ │ └── index.tsx
│ │ ├── PortionsSelect.tsx
│ │ ├── defaultPortions.ts
│ │ ├── formatAmount.ts
│ │ ├── getAmountFromPortionsToGrams.ts
│ │ ├── getIngredientPortionDescription.ts
│ │ ├── getPortionDescription.ts
│ │ ├── getToGramsConversionFactor.ts
│ │ ├── index.ts
│ │ ├── types.ts
│ │ ├── useGetAmount.ts
│ │ ├── useGetToGramsConversionFactor.ts
│ │ └── usePortionsStore.ts
│ ├── react-app-env.d.ts
│ ├── reportWebVitals.ts
│ ├── setupTests.ts
│ ├── stats/
│ │ ├── AmountInput.tsx
│ │ ├── EnergyStat.tsx
│ │ ├── PdfStat.tsx
│ │ ├── PdfStatsLayout.tsx
│ │ ├── Stat.tsx
│ │ ├── StatValueDetail.tsx
│ │ ├── StatsFormFields/
│ │ │ ├── MacrosFormFields.tsx
│ │ │ ├── ReavealButton.tsx
│ │ │ ├── StatFormField/
│ │ │ │ ├── ReadOnlyInput.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── types.ts
│ │ │ │ └── useGetInputElement.tsx
│ │ │ ├── VitaminsAndMineralsFormFields.tsx
│ │ │ ├── index.tsx
│ │ │ ├── useGetDailyValuePercent.ts
│ │ │ └── useGetValue.ts
│ │ ├── StatsLayout.tsx
│ │ ├── amountAsNumber.ts
│ │ ├── calculations/
│ │ │ ├── aggregateStats.ts
│ │ │ ├── getDailyValuePercent.ts
│ │ │ ├── getEnergiesEstimates.ts
│ │ │ ├── getMacrosPercents.ts
│ │ │ ├── getStatsTree.ts
│ │ │ ├── index.ts
│ │ │ └── roundMacrosPercents.ts
│ │ ├── getUnit.ts
│ │ ├── index.ts
│ │ ├── objectFromNutritionDataKeys.ts
│ │ ├── statsVariants.ts
│ │ ├── types.ts
│ │ ├── useMealsStatsStore.ts
│ │ ├── useUpdateMealStats.ts
│ │ └── useVariantStats.ts
│ ├── theme/
│ │ ├── colors.ts
│ │ ├── components/
│ │ │ ├── Alert.ts
│ │ │ ├── Button.ts
│ │ │ ├── Divider.ts
│ │ │ ├── Input.ts
│ │ │ ├── Textarea.ts
│ │ │ └── index.ts
│ │ ├── getComputedColorFromChakra.ts
│ │ ├── index.ts
│ │ └── styles.ts
│ ├── undoRedo/
│ │ ├── UndoRedoButtons/
│ │ │ ├── RedoButton.tsx
│ │ │ ├── UndoButton.tsx
│ │ │ └── index.tsx
│ │ ├── appLocation.ts
│ │ ├── deltasStack.ts
│ │ ├── index.ts
│ │ ├── useDietFormVersionsStore.ts
│ │ └── useKeyboard.ts
│ └── variants/
│ ├── PdfVariantsList/
│ │ ├── PdfVariantItem.tsx
│ │ └── index.tsx
│ ├── VariantStats/
│ │ ├── EnergyStat.tsx
│ │ ├── VariantStat.tsx
│ │ └── index.tsx
│ ├── VariantsDetailsModal/
│ │ ├── Content/
│ │ │ ├── FormFields.tsx
│ │ │ ├── VariantsDetailsFormProvider.tsx
│ │ │ ├── index.tsx
│ │ │ ├── useVariantFormEvents.ts
│ │ │ └── variantsDetailsForm.ts
│ │ └── index.tsx
│ ├── VariantsList/
│ │ ├── AddVariantButton.tsx
│ │ ├── ScrollButtons.tsx
│ │ ├── VariantItem/
│ │ │ ├── PresenceAnimation.tsx
│ │ │ ├── getMenuOrDrawerItems.tsx
│ │ │ ├── index.tsx
│ │ │ ├── useScrollIntoView.ts
│ │ │ └── useVariantFormEvents.ts
│ │ ├── VariantNameModal/
│ │ │ ├── Content.tsx
│ │ │ ├── VariantNameFormProvider.tsx
│ │ │ ├── index.tsx
│ │ │ ├── useSubmitVariantNameForm.ts
│ │ │ └── variantNameForm.ts
│ │ ├── VariantsMenuOrDrawer/
│ │ │ ├── Drawer/
│ │ │ │ ├── VariantItem.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── Menu.tsx
│ │ │ ├── Trigger.tsx
│ │ │ └── index.tsx
│ │ ├── index.tsx
│ │ ├── useScrollState.ts
│ │ └── useVariantFormEvents.ts
│ ├── getVariantFormIndexAfterRemove.ts
│ ├── index.ts
│ ├── useGetVariantFormStatsTree.ts
│ ├── useVariantsFormsActions.ts
│ └── variantForm.ts
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
================================================
FILE: .husky/.gitignore
================================================
_
================================================
FILE: .husky/pre-commit
================================================
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
================================================
FILE: .prettierignore
================================================
**/node_modules
**/dist
**/package.json
**/yarn.lock
**/package-lock.json
**/.eslintrc.json
**/tsconfig.json
================================================
FILE: .prettierrc
================================================
{
"arrowParens": "avoid",
"singleQuote": true,
"semi": false,
"printWidth": 80
}
================================================
FILE: .vscode/settings.json
================================================
{
"editor.formatOnPaste": true,
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Vladimir Angelov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
Calories-In
A web-based meal plan editor for people who prepare all of their food.
Live version: https://calories-in.com
Demo video: https://tella.video/calories-in-4onp
## Background
The idea was born out of my experience of trying to find a better alternative to Google Sheets for calculating the macros of my meal plans. I wanted to be able to do this on desktop as it's more convenient but nothing really felt fast and simple enough.
A huge inspiration for me has been [excalidraw.com](http://excalidraw.com).
## Notable libraries
- [Chakra UI](https://chakra-ui.com/)
- [React Beautiful Dnd](https://github.com/atlassian/react-beautiful-dnd)
- [React-pdf](https://react-pdf.org/)
- [Comlink-loader](https://github.com/GoogleChromeLabs/comlink-loader)
- [React window](https://github.com/bvaughn/react-window)
- [Fuse.js](https://fusejs.io/)
- [Framer Motion](https://www.framer.com/motion/)
- [Feather icons](https://feathericons.com/)
## Available Scripts
In the project directory, you can run:
### `yarn start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
### `yarn build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
================================================
FILE: package.json
================================================
{
"name": "energytab",
"version": "0.1.0",
"private": true,
"dependencies": {
"@chakra-ui/react": "^1.3.4",
"@emotion/css": "^11.1.3",
"@emotion/react": "^11.1.5",
"@emotion/styled": "^11.1.5",
"@hookform/resolvers": "^2.6.0",
"@react-hook/resize-observer": "^1.2.0",
"@react-pdf/renderer": "^2.0.19",
"@szhsin/react-menu": "1.11.0",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-window": "^1.8.3",
"@types/smoothscroll-polyfill": "^0.3.1",
"@types/uuid": "^8.3.0",
"comlink-loader": "^2.0.0",
"focus-visible": "^5.2.0",
"format-quantity": "^1.0.1",
"framer-motion": "^3.10.0",
"fuse.js": "^6.4.6",
"immer": "^9.0.5",
"jsondiffpatch": "^0.4.1",
"numeric-quantity": "^1.0.2",
"pretty-bytes": "^5.6.0",
"react": "^17.0.1",
"react-beautiful-dnd": "13.0.0",
"react-device-detect": "^1.17.0",
"react-dom": "^17.0.1",
"react-feather": "^2.0.9",
"react-hook-form": "7.8.5",
"react-merge-refs": "^1.1.0",
"react-scripts": "4.0.3",
"react-window": "^1.8.6",
"scroll-polyfill": "^1.0.1",
"source-map-explorer": "^2.5.2",
"typescript": "^4.1.2",
"uuid": "^8.3.2",
"web-vitals": "^1.0.1",
"yup": "^0.32.9"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"format": "prettier --write src/**/*.{ts,tsx}",
"lint": "tsc --noEmit && eslint src/**/*.{ts,tsx}",
"prepare": "husky install",
"analyze": "source-map-explorer 'build/static/js/*.js'"
},
"lint-staged": {
"src/**/*.{ts,tsx}": [
"yarn lint"
],
"*.{ts,tsx}": "prettier --write"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/react-beautiful-dnd": "^13.0.0",
"@types/react-custom-scroll": "^4.2.1",
"@types/react-custom-scrollbars": "^4.0.7",
"husky": "^6.0.0",
"lint-staged": "^10.5.4",
"prettier": "^2.2.1"
}
}
================================================
FILE: public/browserconfig.xml
================================================
#da532c
================================================
FILE: public/index.html
================================================
Calories-In
================================================
FILE: public/robots.txt
================================================
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
================================================
FILE: public/site.webmanifest
================================================
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#319795",
"background_color": "#319795",
"display": "standalone"
}
================================================
FILE: src/App.tsx
================================================
import { ChakraProvider } from '@chakra-ui/react'
import { MainLayout } from 'layout'
import 'focus-visible/dist/focus-visible'
import theme from 'theme'
import { FoodsStoreProvider } from 'foods'
import { loadFoods } from 'foods/persistence'
import { OneTimeCheckStoreProvider, ScreenSizeProvider } from 'general'
import { DietEditor } from 'diets'
import { useState } from 'react'
import { PortionsStoreProvider } from 'portions'
import 'scroll-polyfill/auto'
function App() {
const [foods] = useState(loadFoods)
return (
)
}
export default App
================================================
FILE: src/diets/DietEditor/DndContextProvider.tsx
================================================
import { useDietFormActions } from 'diets'
import { ReactNode } from 'react'
import { DragDropContext, DropResult } from 'react-beautiful-dnd'
type Props = {
children: ReactNode
}
function DndContextProvider({ children }: Props) {
const dietFormActions = useDietFormActions()
const onDragEnd = (dropResult: DropResult) => {
const { source, destination, type } = dropResult
if (!destination) {
return
}
if (type === 'variantsList') {
dietFormActions.moveVariantForm(source.index, destination.index)
} else if (type === 'mealsList') {
dietFormActions.moveMealForm(source.index, destination.index)
} else if (type === 'ingredientsList') {
dietFormActions.moveIngredientForm(
source.droppableId,
source.index,
destination.droppableId,
destination.index
)
}
}
return {children}
}
export default DndContextProvider
================================================
FILE: src/diets/DietEditor/Form/About.tsx
================================================
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Button,
Text,
ListItem,
List,
ListIcon,
} from '@chakra-ui/react'
import { CheckCircle } from 'react-feather'
type Props = {
isOpen: boolean
onClose: () => void
}
function About({ isOpen, onClose }: Props) {
return (
About
Hi, I'm Vladimir, the person behind this project.
Calories-In
{' '}
is made for people who follow meal plans that involve preparing
everything by yourself and gives them full control to fine tune
the nutritional values.
The idea was born out of my experience of trying to find a better
alternative to Google Sheets for calculating the macros of my own
meal plans. I wanted to be able to do this on desktop as it's more
convenient but nothing really felt fast and simple enough.
The main differences to other apps in this space are:
Faster search
There are actually not that many foods you need when you
prepare everything yourself. This means all of the food data
can be downloaded beforehand which makes the search super
fast. Of course you can add your own foods if you'd like.{' '}
Undo/Redo
Building a plan from scratch or updating an existing one
involves some back and forth choosing the right foods and
adjusting their amounts. This is especially true if you want
to be as close as possible to a specific calorie limit and
have your macros be a certain percentages split.
Faster export
Creating the PDF file for your meal plan is done entirely
inside the browser. It does not involve generating and
downloading it from a server. This means I can keep the cost
of running the website low and you get your file in just a few
seconds.
Simpler
There are no other pages except the editor. Most of the other
tools are bloated with additional features for professionals,
such as managing clients, creating invoices, etc.
Fully mobile
You can use your phone or tablet to build your meal plans
right from your browser. If you add the app to your home
screen it will look and feel almost like a native one.
)
}
export default About
================================================
FILE: src/diets/DietEditor/Form/Controls/ExportButton.tsx
================================================
import { ScreenSize, useScreenSize } from 'general'
import { Button, ButtonProps, IconButton } from '@chakra-ui/react'
import { Share } from 'react-feather'
import { canExportDietForm } from 'diets/persistence'
import { useDietForm } from 'diets'
type Props = {} & ButtonProps
function ExportButton({ ...rest }: Props) {
const screenSize = useScreenSize()
const dietForm = useDietForm()
const canExport = canExportDietForm(dietForm)
const commonProps: ButtonProps = {
isDisabled: !canExport,
...rest,
}
if (screenSize >= ScreenSize.Medium) {
return (
}
variant="solid"
colorScheme="teal"
size="md"
{...commonProps}
>
Export
)
}
return (
}
{...commonProps}
/>
)
}
export default ExportButton
================================================
FILE: src/diets/DietEditor/Form/Controls/MenuOrDrawer.tsx
================================================
import { chakra } from '@chakra-ui/react'
import { Download, List, MoreHorizontal, Trash } from 'react-feather'
import {
MenuOrDrawer as MenuOrDrawerBase,
MenuOrDrawerItem,
MenuOrDrawerSeparator,
ScreenSize,
useScreenSize,
} from 'general'
const DownloadStyled = chakra(Download)
const ListStyled = chakra(List)
const TrashStyled = chakra(Trash)
type Props = {
onImport: () => void
onClear: () => void
onViewFoods: () => void
}
function MenuOrDrawer({ onImport, onClear, onViewFoods }: Props) {
const screenSize = useScreenSize()
const items = [
,
}
onClick={onImport}
>
Import meal plan
,
}
onClick={onViewFoods}
>
Manage foods
,
]
if (screenSize <= ScreenSize.Small) {
items.unshift(
}
onClick={onClear}
>
Clear
)
}
return (
}
aria-label="More actions"
>
{items}
)
}
export default MenuOrDrawer
================================================
FILE: src/diets/DietEditor/Form/Controls/Name.tsx
================================================
import { useDietForm, useDietFormActions } from 'diets'
import { Editable, EditableInput, EditablePreview } from '@chakra-ui/react'
import { ChangeEvent, useEffect, useRef } from 'react'
import getComputedColorFromChakra from 'theme/getComputedColorFromChakra'
import { canExportDietForm } from 'diets/persistence'
function Name() {
const dietForm = useDietForm()
const dietFormActions = useDietFormActions()
const editablePreviewRef = useRef(null)
const focusedForDietFieldIdMap = useRef>(
{}
)
useEffect(() => {
if (
!canExportDietForm(dietForm) &&
editablePreviewRef.current &&
!focusedForDietFieldIdMap.current[dietForm.fieldId]
) {
editablePreviewRef.current.focus()
focusedForDietFieldIdMap.current[dietForm.fieldId] = true
}
}, [dietForm])
function onNameChange(event: ChangeEvent) {
const { value } = event.target
dietFormActions.updateDietForm({ name: value })
}
const boxShadowColor = getComputedColorFromChakra('teal.400')
return (
)
}
export default Name
================================================
FILE: src/diets/DietEditor/Form/Controls/index.tsx
================================================
import { Flex, useDisclosure, Button } from '@chakra-ui/react'
import { UndoRedoButtons, useKeyboard } from 'undoRedo'
import { getDietForm, useDietFormActions } from 'diets'
import { useImportDietForm, ExportModal } from 'diets/persistence'
import {
FoodsListModal,
MissingFoodsModal,
useImportFoods,
} from 'foods/persistence'
import { FoodsDrawer } from 'foods'
import { Trash } from 'react-feather'
import MenuOrDrawer from './MenuOrDrawer'
import Name from './Name'
import { ScreenSize, useScreenSize } from 'general'
import ExportButton from './ExportButton'
function Controls() {
const dietFormActions = useDietFormActions()
const exportModalDisclosure = useDisclosure()
const missingFoodsModalDisclosure = useDisclosure()
const { onLoadFromFile } = useImportDietForm({ missingFoodsModalDisclosure })
const foodsListModalDisclosure = useDisclosure()
const importFoods = useImportFoods({ foodsListModalDisclosure })
const foodsDrawerDisclosure = useDisclosure()
const screenSize = useScreenSize()
useKeyboard()
function onClear() {
dietFormActions.setDietForm(getDietForm())
}
return (
{screenSize >= ScreenSize.Medium && (
}
size="md"
onClick={onClear}
mr={2}
>
Clear
)}
)
}
export default Controls
================================================
FILE: src/diets/DietEditor/Form/Footer.tsx
================================================
import { Box, HStack, Button, Divider, Link, BoxProps } from '@chakra-ui/react'
type Props = {
onAbout: () => void
} & BoxProps
function Footer({ onAbout, ...rest }: Props) {
return (
Terms
Disclaimer
)
}
export default Footer
================================================
FILE: src/diets/DietEditor/Form/index.tsx
================================================
import { useDietForm, useScrollManager } from 'diets'
import { DietFormVersionsStoreProvider } from 'undoRedo'
import { useRef } from 'react'
import { Page, PageHeader, PageBody } from 'layout'
import { MealsList } from 'meals'
import useDietFormEvents from './useDietFormEvents'
import { Box, useDisclosure, Flex } from '@chakra-ui/react'
import { ScreenSize, useElementHeight, useScreenSize } from 'general'
import Controls from './Controls'
import { FoodsDrawer } from 'foods'
import { VariantsList, VariantStats } from 'variants'
import useVariantFormEvents from './useVariantFormActions'
import About from './About'
import Footer from './Footer'
function Form() {
const horizontalScrollRef = useRef(null)
const dietForm = useDietForm()
const { variantsForms } = dietForm
const selectedVariantForm = variantsForms[dietForm.selectedVariantFormIndex]
const scrollManager = useScrollManager({
selectedVariantForm,
horizontalScrollRef,
})
const foodsDrawerDisclosure = useDisclosure()
const dietFormEvents = useDietFormEvents({
scrollManager,
foodsDrawerDisclosure,
})
const {
elementHeight: headerHeight,
elementRef: headerRef,
} = useElementHeight()
const variantFormEvents = useVariantFormEvents({ scrollManager })
const screenSize = useScreenSize()
const aboutModalDisclosure = useDisclosure()
return (
{screenSize >= ScreenSize.Large && (
)}
)
}
export default Form
================================================
FILE: src/diets/DietEditor/Form/useDietFormEvents.ts
================================================
import { UseDisclosureReturn } from '@chakra-ui/hooks'
import { DietForm, useDietFormActions, ScrollManager } from 'diets'
import { Food } from 'foods'
import { getIngredient } from 'ingredients'
import { getMealForm } from 'meals'
import { AppLocation } from 'undoRedo'
type Params = {
scrollManager: ScrollManager
foodsDrawerDisclosure: UseDisclosureReturn
}
function useDietFormEvents({ scrollManager, foodsDrawerDisclosure }: Params) {
const dietFormActions = useDietFormActions()
const { setScrollState } = scrollManager
function onMealAdded(foods: Food[], mealName?: string) {
foodsDrawerDisclosure.onClose()
const ingredients = foods.map(getIngredient)
const mealForm = getMealForm({ name: mealName as string, ingredients })
dietFormActions.appendMealForm(mealForm)
}
function onUndoOrRedo(
form: DietForm,
{ scrollTop, scrollLeft, variantIndex }: AppLocation
) {
const finalVariantIndex = form.variantsForms[variantIndex]
? variantIndex
: form.selectedVariantFormIndex
dietFormActions.updateDietForm({
...form,
selectedVariantFormIndex: finalVariantIndex,
})
setScrollState({ top: scrollTop, left: scrollLeft })
}
return {
onUndoOrRedo,
onMealAdded,
}
}
export default useDietFormEvents
================================================
FILE: src/diets/DietEditor/Form/useVariantFormActions.ts
================================================
import { VariantForm } from 'variants'
import { useCallback } from 'react'
import { ScrollManager } from 'diets/useScrollManager'
type Params = {
scrollManager: ScrollManager
}
function useVariantFormEvents({ scrollManager }: Params) {
const { setScrollState, getCachedScrollTop } = scrollManager
const onVariantFormSelect = useCallback(
(variantForm: VariantForm) => {
setScrollState({ top: getCachedScrollTop(variantForm.fieldId) })
},
[setScrollState, getCachedScrollTop]
)
const onVariantFormCopy = useCallback(() => {
setScrollState({ top: 0 })
}, [setScrollState])
return {
onVariantFormCopy,
onVariantFormSelect,
}
}
export default useVariantFormEvents
================================================
FILE: src/diets/DietEditor/index.tsx
================================================
import { DietFormStoreProvider } from 'diets'
import Form from './Form'
import { useOneTimeCheckActions } from 'general'
import DndContextProvider from './DndContextProvider'
import { MealsStatsStoreProvider } from 'stats'
import { useState } from 'react'
import { loadLastOrDefaultDietForm } from 'diets/persistence'
function DietEditor() {
const oneTimeCheckActions = useOneTimeCheckActions()
const [dietForm] = useState(loadLastOrDefaultDietForm)
return (
<>
>
)
}
export default DietEditor
================================================
FILE: src/diets/PdfDietEditor.tsx
================================================
import ReactPDF, {
Document,
Page,
Font,
StyleSheet,
View,
} from '@react-pdf/renderer'
import { Food } from 'foods'
import { Portion } from 'portions'
import { ReactElement } from 'react'
import { StatsTree } from 'stats/calculations/getStatsTree'
import getComputedColorFromChakra from 'theme/getComputedColorFromChakra'
import PdfVariantItem from 'variants/PdfVariantsList/PdfVariantItem'
import { DietForm } from './dietForm'
type Props = {
dietForm: DietForm
foodsById: Record
portionsById: Record
dietFormStatsTree: StatsTree
} & ReactPDF.DocumentProps
function PdfDietEditor({
dietForm,
foodsById,
portionsById,
dietFormStatsTree,
...rest
}: Props) {
const { variantsForms } = dietForm
const variantItemsElements: ReactElement[] = []
variantsForms.forEach((variantForm, index) => {
const { mealsForms } = variantForm
const { stats, subtrees } = dietFormStatsTree.subtrees[index]
if (mealsForms.length > 0) {
variantItemsElements.push(
)
}
})
return (
{variantItemsElements}
)
}
const styles = StyleSheet.create({
page: {
fontFamily: 'Roboto',
paddingBottom: 12,
},
})
Font.register({
family: 'Roboto',
fonts: [
{
src:
'https://fontlibrary.org/assets/fonts/roboto/4f8c3c9bbdde908a86daabfe666d2f61/ac3f799d5bbaf5196fab15ab8de8431c/RobotoRegular.ttf',
fontWeight: 'normal',
},
{
src:
'https://fontlibrary.org/assets/fonts/roboto/4f8c3c9bbdde908a86daabfe666d2f61/fe13e4170719c2fc586501e777bde143/RobotoMedium.ttf',
fontWeight: 'medium',
},
{
src:
'https://fontlibrary.org/assets/fonts/roboto/4f8c3c9bbdde908a86daabfe666d2f61/d329cc8b34667f114a95422aaad1b063/RobotoBold.ttf',
fontWeight: 'bold',
},
],
})
export default PdfDietEditor
================================================
FILE: src/diets/dietForm.ts
================================================
import { Diet } from 'diets'
import { getVariantForm, VariantForm } from 'variants'
import { v4 as uuidv4 } from 'uuid'
type DietForm = {
fieldId: string
name: string
selectedVariantFormIndex: number
variantsForms: VariantForm[]
}
function getDietForm(diet?: Diet): DietForm {
const variantsForms = [getVariantForm('Day 1')]
const fieldId = uuidv4()
if (diet) {
return {
fieldId,
name: diet.name,
variantsForms,
selectedVariantFormIndex: 0,
}
}
return {
fieldId,
name: 'Untitled',
variantsForms,
selectedVariantFormIndex: 0,
}
}
export type { DietForm }
export { getDietForm }
================================================
FILE: src/diets/index.ts
================================================
export * from './dietForm'
export { default as useDietFormStore } from './useDietFormStore'
export * from './useDietFormStore'
export { default as DietEditor } from './DietEditor'
export * from './types'
export { default as useGetDietFormStatsTree } from './useGetDietFormStatsTree'
export { default as useScrollManager } from './useScrollManager'
export * from './useScrollManager'
================================================
FILE: src/diets/persistence/ExportModal/Content/Exporter/index.tsx
================================================
import { Loader } from 'general'
import {
Alert,
AlertIcon,
AlertTitle,
AlertDescription,
} from '@chakra-ui/react'
import usePdfExport from './usePdfExport'
type Props = {
onUpdate: (blob: Blob, url: string) => void
}
function Exporter({ onUpdate }: Props) {
const { isLoading, error } = usePdfExport({ onUpdate })
if (isLoading) {
return
}
return (
{error
? 'Something went wrong while creating your pdf file'
: 'Your PDF file is ready'}
{!error && (
Downloading this plan will allow you to import it later if you need to
update it.
)}
)
}
export default Exporter
================================================
FILE: src/diets/persistence/ExportModal/Content/Exporter/usePdfExport.ts
================================================
import { useDietForm, useGetDietFormStatsTree } from 'diets'
import { useFoods } from 'foods'
import { usePortions } from 'portions'
import { useEffect, useState } from 'react'
import Worker from './worker'
import { minDelay, useRunIfNotUnmounted } from 'general'
const worker = new Worker()
type Params = {
onUpdate: (blob: Blob, url: string) => void
}
function usePdfExport({ onUpdate }: Params) {
const dietForm = useDietForm()
const { foodsById } = useFoods()
const { portionsById } = usePortions()
const getDietFormStatsTree = useGetDietFormStatsTree()
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState()
const runIfNotUnmounted = useRunIfNotUnmounted()
useEffect(() => {
async function run() {
const dietFormStatsTree = getDietFormStatsTree(dietForm)
const startDate = new Date()
try {
setIsLoading(true)
const blob = await worker.getDietPdfBlob({
dietForm,
dietFormStatsTree,
foodsById,
portionsById,
})
await minDelay(startDate)
runIfNotUnmounted(() => {
setIsLoading(false)
const url = URL.createObjectURL(blob)
onUpdate(blob, url)
})
} catch (error) {
await minDelay(startDate)
runIfNotUnmounted(() => {
setIsLoading(false)
setError(error)
})
}
}
run()
}, [
dietForm,
foodsById,
portionsById,
getDietFormStatsTree,
onUpdate,
runIfNotUnmounted,
])
return {
isLoading,
error,
}
}
export default usePdfExport
================================================
FILE: src/diets/persistence/ExportModal/Content/Exporter/worker/custom.d.ts
================================================
declare module 'comlink-loader!*' {
import { Params } from './types'
class WebpackWorker extends Worker {
constructor()
getDietPdfBlob(data: Params): Promise
}
export = WebpackWorker
}
================================================
FILE: src/diets/persistence/ExportModal/Content/Exporter/worker/index.ts
================================================
// eslint-disable-next-line
import Worker from 'comlink-loader!./worker'
export default Worker
================================================
FILE: src/diets/persistence/ExportModal/Content/Exporter/worker/types.ts
================================================
import { DietForm } from 'diets/dietForm'
import { Food } from 'foods/types'
import { Portion } from 'portions/types'
import { StatsTree } from 'stats/calculations'
type Params = {
dietForm: DietForm
foodsById: Record
portionsById: Record
dietFormStatsTree: StatsTree
}
export type { Params }
================================================
FILE: src/diets/persistence/ExportModal/Content/Exporter/worker/worker.tsx
================================================
import { pdf } from '@react-pdf/renderer'
if (process.env.NODE_ENV !== 'production') {
const t: any = global
t.$RefreshReg$ = () => {}
t.$RefreshSig$ = () => () => {}
}
async function getDietPdfBlob(data: any) {
const PdfDietEditor = require('diets/PdfDietEditor').default
const document = (
)
return pdf(document).toBlob()
}
export { getDietPdfBlob }
================================================
FILE: src/diets/persistence/ExportModal/Content/index.tsx
================================================
import {
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Button,
VStack,
Text,
} from '@chakra-ui/react'
import { useState, useCallback } from 'react'
import { DownloadButton } from 'persistence'
import { useDietForm } from 'diets'
import Exporter from './Exporter'
type Props = {
onClose: () => void
}
function Content({ onClose }: Props) {
const [blob, setBlob] = useState()
const [url, setUrl] = useState()
const dietForm = useDietForm()
const onUpdate = useCallback((blob: Blob, url: string) => {
setBlob(blob)
setUrl(url)
}, [])
function onViewInBrowser() {
window.open(url, '_blank')
}
return (
Export{' '}
{dietForm.name}
{blob && url && (
)}
{blob && url && (
)}
)
}
export default Content
================================================
FILE: src/diets/persistence/ExportModal/index.tsx
================================================
import { Modal, ModalOverlay } from '@chakra-ui/react'
import Content from './Content'
type Props = {
isOpen: boolean
onClose: () => void
}
function ExportModal({ isOpen, onClose }: Props) {
return (
)
}
export default ExportModal
================================================
FILE: src/diets/persistence/canExportDietForm.ts
================================================
import { DietForm } from 'diets'
function canExportDietForm(dietForm: DietForm) {
const { variantsForms } = dietForm
return variantsForms.some(({ mealsForms }) => {
return mealsForms.length > 0
})
}
export default canExportDietForm
================================================
FILE: src/diets/persistence/hasMissingFoods.ts
================================================
import { DietForm } from 'diets'
import { Food, FoodId } from 'foods'
function hasMissingFoods(dietForm: DietForm, foodsById: Record) {
const { variantsForms } = dietForm
for (const variantForm of variantsForms) {
const { mealsForms } = variantForm
for (const mealForm of mealsForms) {
const { ingredientsForms } = mealForm
for (const ingredientForm of ingredientsForms) {
const food = foodsById[ingredientForm.foodId]
if (!food) {
return true
}
}
}
}
return false
}
export default hasMissingFoods
================================================
FILE: src/diets/persistence/index.ts
================================================
export { default as ExportModal } from './ExportModal'
export { default as useImportDietForm } from './useImportDietForm'
export { default as parseDietForm } from './parseDietForm'
export { default as hasMissingFoods } from './hasMissingFoods'
export { default as loadLastOrDefaultDietForm } from './loadLastOrDefaultDietForm'
export { default as canExportDietForm } from './canExportDietForm'
================================================
FILE: src/diets/persistence/loadLastOrDefaultDietForm.ts
================================================
import { getDietForm } from 'diets'
function loadLastOrDefaultDietForm() {
const savedValue = localStorage.getItem('lastDietForm')
if (savedValue) {
try {
return JSON.parse(savedValue)
} catch (error) {
return getDietForm()
}
}
return getDietForm()
}
export default loadLastOrDefaultDietForm
================================================
FILE: src/diets/persistence/parseDietForm.ts
================================================
import { DietForm } from 'diets'
import { fixWhiteSpace } from 'persistence'
function getLocation(text: string) {
const subject = '/Subject'
const startIndex = text.indexOf('/Subject')
const endIndex = text.indexOf('R', startIndex)
if (startIndex < 0 || endIndex < 0) {
throw new SyntaxError()
}
const locatioPrefix = text.slice(startIndex + subject.length, endIndex).trim()
return `${locatioPrefix} obj`
}
function getData(location: string, text: string) {
const startIndex = text.indexOf(location)
const endIndex = text.indexOf('endobj', startIndex)
if (startIndex < 0 || endIndex < 0) {
throw new SyntaxError()
}
return text.slice(startIndex + location.length + 2, endIndex - 2)
}
function parseDietForm(text: string) {
const location = getLocation(text)
const data = getData(location, text)
const dietForm = JSON.parse(data, (key: string, value) => {
if (key === 'notes') {
return fixWhiteSpace(value)
}
return value
}) as DietForm
return dietForm
}
export default parseDietForm
================================================
FILE: src/diets/persistence/useDietImportErrors.tsx
================================================
import { useToast } from '@chakra-ui/toast'
import { Text, Button, UseDisclosureReturn } from '@chakra-ui/react'
type Params = {
missingFoodsModalDisclosure: UseDisclosureReturn
}
function useDietImportErrors({ missingFoodsModalDisclosure }: Params) {
const toast = useToast()
function onLearnAboutMissingFoods() {
toast.closeAll()
missingFoodsModalDisclosure.onOpen()
}
function onMissingFoods() {
toast({
isClosable: true,
position: 'top',
title: 'File imported',
description: (
Warning: Foods missing.{' '}
),
status: 'warning',
duration: null,
})
}
return {
onMissingFoods,
missingFoodsModalDisclosure,
}
}
export default useDietImportErrors
================================================
FILE: src/diets/persistence/useImportDietForm.ts
================================================
import { selectFile, readFile } from 'persistence'
import { useFoods } from 'foods'
import { useDietFormActions } from 'diets'
import { hasMissingFoods, parseDietForm } from 'diets/persistence'
import useFileImportError from 'persistence/useImportFileError'
import { useToast } from '@chakra-ui/toast'
import useDietImportErrors from './useDietImportErrors'
import { UseDisclosureReturn } from '@chakra-ui/hooks'
type Params = {
missingFoodsModalDisclosure: UseDisclosureReturn
}
function useImportDietForm({ missingFoodsModalDisclosure }: Params) {
const { foodsById } = useFoods()
const dietFormActions = useDietFormActions()
const fileImportError = useFileImportError()
const dietImportErrors = useDietImportErrors({ missingFoodsModalDisclosure })
const toast = useToast()
async function onLoadFromFile() {
const file = await selectFile('application/pdf')
try {
const text = await readFile(file)
const dietForm = parseDietForm(text)
if (hasMissingFoods(dietForm, foodsById)) {
dietImportErrors.onMissingFoods()
} else {
toast({
status: 'success',
position: 'top',
title: 'Meal plan imported',
duration: 2000,
isClosable: true,
})
}
dietFormActions.setDietForm(dietForm)
} catch (error: any) {
fileImportError.onError({ error, file })
}
}
return {
onLoadFromFile,
missingFoodsModalDisclosure: dietImportErrors.missingFoodsModalDisclosure,
}
}
export default useImportDietForm
================================================
FILE: src/diets/types.ts
================================================
import { Meal } from 'meals'
type Diet = {
id: number
name: string
meals: Meal[]
}
export type { Diet }
================================================
FILE: src/diets/useDietFormStore.ts
================================================
import { useCallback, useState } from 'react'
import { DietForm } from './dietForm'
import { useVariantsFormsActions, VariantsFormsActions } from 'variants'
import { useMealsFormsActions, MealsFormsActions } from 'meals'
import { useCallbacksMemo, makeStoreProvider } from 'general'
import {
useIngredientsFormsActions,
IngredientsFormsActions,
} from 'ingredients'
import { OneTimeCheckActions } from 'general'
import { useSaveValue } from 'persistence'
export type Params = {
initialDietForm: DietForm
oneTimeCheckActions: OneTimeCheckActions
}
type Actions = VariantsFormsActions &
MealsFormsActions &
IngredientsFormsActions
function useDietFormStore({
initialDietForm,
oneTimeCheckActions,
}: Params) {
const [dietForm, setDietForm] = useState(initialDietForm)
useSaveValue({ value: dietForm, key: 'lastDietForm' })
const variantsFormsActions = useVariantsFormsActions({
setDietForm,
oneTimeCheckActions,
})
const mealsFormsActions = useMealsFormsActions({
setDietForm,
oneTimeCheckActions,
})
const ingredientsFormsActions = useIngredientsFormsActions({
setDietForm,
oneTimeCheckActions,
})
const updateDietForm = useCallback(
(partialDietForm: Partial) => {
setDietForm(dietForm => {
return {
...dietForm,
...partialDietForm,
}
})
},
[setDietForm]
)
const ownActions = {
setDietForm,
updateDietForm,
}
const actions: Actions & typeof ownActions = useCallbacksMemo({
...ownActions,
...mealsFormsActions,
...variantsFormsActions,
...ingredientsFormsActions,
})
return [dietForm, actions] as const
}
const [
DietFormStoreProvider,
useDietForm,
useDietFormActions,
] = makeStoreProvider(useDietFormStore)
export { DietFormStoreProvider, useDietForm, useDietFormActions }
export default useDietFormStore
================================================
FILE: src/diets/useGetDietFormStatsTree.ts
================================================
import { StatsTree, getStatsTree } from 'stats'
import { DietForm } from './dietForm'
import { useGetVariantFormStatsTree } from 'variants'
import { useCallback } from 'react'
function useGetDietFormStatsTree() {
const getVariantFormStatsTree = useGetVariantFormStatsTree()
const getDietFormStatsTree2 = useCallback(
(dietForm: DietForm): StatsTree => {
const subtrees = dietForm.variantsForms.map(variantForm =>
getVariantFormStatsTree(variantForm)
)
return getStatsTree({
id: dietForm.fieldId,
subtrees,
calculateAvg: true,
})
},
[getVariantFormStatsTree]
)
return getDietFormStatsTree2
}
export default useGetDietFormStatsTree
================================================
FILE: src/diets/useScrollManager.ts
================================================
import { VariantForm } from 'variants'
import { useState, useRef, useEffect, RefObject, useCallback } from 'react'
type ScrollState = {
top?: number
left?: number
}
type Params = {
selectedVariantForm: VariantForm
horizontalScrollRef: RefObject
}
function useScrollManager({
selectedVariantForm,
horizontalScrollRef,
}: Params) {
const scrollTopCacheRef = useRef>({})
const [scrollState, setScrollState] = useState({
top: 0,
left: 0,
})
const getCachedScrollTop = useCallback((variantFormFieldId: string) => {
return scrollTopCacheRef.current[variantFormFieldId] || 0
}, [])
useEffect(() => {
function onScroll() {
scrollTopCacheRef.current[selectedVariantForm.fieldId] = window.scrollY
}
window.addEventListener('scroll', onScroll)
return () => {
window.removeEventListener('scroll', onScroll)
}
}, [selectedVariantForm.fieldId])
useEffect(() => {
const { top, left } = scrollState
if (top !== undefined) {
window.scroll({ top })
}
if (left !== undefined && horizontalScrollRef.current) {
horizontalScrollRef.current.scrollLeft = left
}
}, [scrollState, horizontalScrollRef])
return {
setScrollState,
getCachedScrollTop,
}
}
type ScrollManager = ReturnType
export type { ScrollManager }
export default useScrollManager
================================================
FILE: src/dom/animateScrollLeft.ts
================================================
import { animate } from 'framer-motion'
import { RefObject } from 'react'
function animateScrollLeft(nodeRef: RefObject, delta: number) {
if (!nodeRef.current) {
return
}
const node = nodeRef.current
animate(node.scrollLeft, node.scrollLeft + delta, {
duration: 0.2,
onUpdate: value => {
node.scrollLeft = value
},
})
}
export default animateScrollLeft
================================================
FILE: src/dom/index.ts
================================================
export { default as animateScrollLeft } from './animateScrollLeft'
export { default as isElementInViewport } from './isElementInViewport'
export { default as useGetRefForId } from './useGetRefForId'
export { default as useScrollTo } from './useScrollTo'
================================================
FILE: src/dom/isElementInViewport.ts
================================================
function isElementInViewport(element: Element) {
const { top, left, bottom, right } = element.getBoundingClientRect()
return (
top >= 0 &&
left >= 0 &&
bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
right <= (window.innerWidth || document.documentElement.clientWidth)
)
}
export default isElementInViewport
================================================
FILE: src/dom/useGetRefForId.ts
================================================
import { createRef, RefObject, useCallback, useRef } from 'react'
type RefsCache = {
[id: number]: RefObject
[id: string]: RefObject
}
function useGetRefForId() {
const cacheRef = useRef>({})
const getRef = useCallback((id: number | string) => {
if (!cacheRef.current[id]) {
cacheRef.current[id] = createRef()
}
return cacheRef.current[id]
}, [])
return getRef
}
export default useGetRefForId
================================================
FILE: src/dom/useScrollTo.ts
================================================
import { useEffect, useRef, useCallback } from 'react'
function useScrollTo() {
const scrollTimeoutRef = useRef()
const didScrollCheckTimeoutRef = useRef()
useEffect(() => {
return () => {
window.clearTimeout(scrollTimeoutRef.current)
}
}, [])
const scrollTo = useCallback((node: HTMLElement) => {
return new Promise(resolve => {
const resolveWihoutScrollTimeout = window.setTimeout(() => {
window.clearTimeout(didScrollCheckTimeoutRef.current)
window.removeEventListener('scroll', listener)
resolve()
}, 100)
function listener() {
window.clearTimeout(scrollTimeoutRef.current)
window.clearTimeout(resolveWihoutScrollTimeout)
scrollTimeoutRef.current = window.setTimeout(() => {
window.removeEventListener('scroll', listener)
resolve()
}, 50)
}
window.addEventListener('scroll', listener)
node.scrollIntoView({
behavior: 'smooth',
block: 'center',
})
})
}, [])
return scrollTo
}
export default useScrollTo
================================================
FILE: src/foods/FoodInfo.tsx
================================================
import { Text, Box, Flex, BoxProps, Link } from '@chakra-ui/react'
import { Food } from 'foods'
import { ReactNode } from 'react'
import { DEFAULT_SERVING_SIZE_IN_GRAMS } from './foodForm'
type Props = {
food: Food
nameNoOfLines?: number
canBeLink?: boolean
notes?: string
energy?: number
children?: ReactNode
} & BoxProps
function FoodInfo({
food,
fontSize,
nameNoOfLines,
energy,
notes,
children,
canBeLink = false,
...rest
}: Props) {
return (
{food.url && canBeLink ? (
{food.name}
) : (
{food.name}
)}
{energy !== undefined && (
{`${Math.round(energy as number)}kcal`}
{' '}
/ {food.servingSizeInGrams || DEFAULT_SERVING_SIZE_IN_GRAMS}g
)}
{children}
)
}
export default FoodInfo
================================================
FILE: src/foods/FoodModal/Content/DeleteConfirmationModal.tsx
================================================
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Button,
Text,
} from '@chakra-ui/react'
type Props = {
isOpen: boolean
onCancel: () => void
onConfirm: () => void
text: string
confirmButtonLabel: String
}
function DeleteConfirmationModal({
isOpen,
onCancel,
onConfirm,
text,
confirmButtonLabel,
}: Props) {
return (
Delete food
{text}
This action cannot be undone.
)
}
export default DeleteConfirmationModal
================================================
FILE: src/foods/FoodModal/Content/FoodFormProvider.tsx
================================================
import { useForm } from 'react-hook-form'
import { yupResolver } from '@hookform/resolvers/yup'
import { ReactNode } from 'react'
import { FormProvider } from 'react-hook-form'
import {
Food,
FoodForm,
foodFormSchema,
FoodFormSchemaContext,
getFoodForm,
useFoods,
} from 'foods'
type Props = {
food?: Food
children: ReactNode
}
function FoodFormProvider({ food, children }: Props) {
const defaultValues = getFoodForm(food)
const { allFoods } = useFoods()
const formMethods = useForm({
defaultValues,
resolver: yupResolver(foodFormSchema),
context: {
allFoods,
food,
},
mode: 'onChange',
})
return {children}
}
export default FoodFormProvider
================================================
FILE: src/foods/FoodModal/Content/Form/Footer.tsx
================================================
import { ModalFooter, Button, HStack } from '@chakra-ui/react'
type Props = {
onClose: () => void
onSubmit: () => void
isEditing: boolean
}
function Footer({ onClose, onSubmit, isEditing }: Props) {
return (
{isEditing && (
)}
)
}
export default Footer
================================================
FILE: src/foods/FoodModal/Content/Form/Header.tsx
================================================
import { ModalHeader, Button } from '@chakra-ui/react'
type Props = {
onClose: () => void
title: string
canEdit: boolean
onToggleEdit: () => void
isEditing: boolean
}
function Header({ title, canEdit, isEditing, onToggleEdit }: Props) {
return (
{title}
{canEdit && (
)}
)
}
export default Header
================================================
FILE: src/foods/FoodModal/Content/Form/Tabs/NutritionFactsFormFields.tsx
================================================
import { Box, FlexProps, VStack } from '@chakra-ui/react'
import { RefObject } from 'react'
import { StatsFormFields, StatFormField } from 'stats'
type Props = {
nameInputRef: RefObject
canEdit: boolean
} & FlexProps
function NutritionFactsFormFields({ nameInputRef, canEdit, ...rest }: Props) {
return (
)
}
export default NutritionFactsFormFields
================================================
FILE: src/foods/FoodModal/Content/Form/Tabs/UrlField.tsx
================================================
import {
Flex,
FormControl,
FormLabel,
Link,
Alert,
AlertIcon,
} from '@chakra-ui/react'
import { Input } from '@chakra-ui/react'
import { Food, FoodForm } from 'foods'
import { useFormContext } from 'react-hook-form'
type Props = {
canEdit: boolean
food?: Food
}
function UrlField({ canEdit, food }: Props) {
const { register } = useFormContext()
return (
{canEdit && (
Add a link will open a web page when the food is clicked. This is
useful if you want to show a specific product.
)}
Link:
{canEdit ? (
) : (
{food?.url}
)}
)
}
export default UrlField
================================================
FILE: src/foods/FoodModal/Content/Form/Tabs/VolumeFormFields.tsx
================================================
import { Flex, Text, HStack, Alert, AlertIcon } from '@chakra-ui/react'
import { Food, FoodForm } from 'foods'
import { PortionsSelect, usePortions } from 'portions'
import { Controller, useFormContext } from 'react-hook-form'
import { AmountInput } from 'stats'
type Props = {
canEdit: boolean
food?: Food
}
function VolumeFields({ canEdit, food }: Props) {
const { register } = useFormContext()
const { portionsById, volumeBasedPortions } = usePortions()
const portion = food?.volume ? portionsById[food.volume.portionId] : undefined
return (
{canEdit && (
Enter the food weight in grams per some volume measurement if you want
to convert between weight and volume (for example: between grams and
cups).
)}
{canEdit && 1 x}
{canEdit ? (
) : (
1 x {`${portion?.singular} (${portion?.millilitersPerAmount} ml)`}
)}
=
{canEdit ? (
(
)}
/>
) : (
{food?.volume?.weightInGrams}g
)}
{canEdit && g}
)
}
export default VolumeFields
================================================
FILE: src/foods/FoodModal/Content/Form/Tabs/index.tsx
================================================
import { Food } from 'foods'
import NutritionFactsFormFields from './NutritionFactsFormFields'
import { RefObject } from 'react'
import {
Tabs as TabsBase,
TabList,
TabPanels,
Tab,
TabPanel,
} from '@chakra-ui/react'
import VolumeFormFields from './VolumeFormFields'
import UrlField from './UrlField'
import { useFormContext } from 'react-hook-form'
type TabName = 'nutrition' | 'volume' | 'link'
type Props = {
nameInputRef: RefObject
food?: Food
isEditing: boolean
selectedTabName: TabName
tabNames: TabName[]
onTabNameChange: (name: TabName) => void
}
function Tabs({
nameInputRef,
food,
isEditing,
selectedTabName,
tabNames,
onTabNameChange,
}: Props) {
const { formState } = useFormContext()
const tabIndex = tabNames.indexOf(selectedTabName)
function onTabIndexChange(index: number) {
onTabNameChange(tabNames[index])
}
return (
Nutrition Facts
{tabNames.includes('volume') && Volume}
{tabNames.includes('link') && Link}
{tabNames.includes('volume') && (
)}
{tabNames.includes('link') && (
)}
)
}
export type { TabName }
export default Tabs
================================================
FILE: src/foods/FoodModal/Content/Form/index.tsx
================================================
import {
ModalContent,
ModalCloseButton,
ModalBody,
Button,
Divider,
Box,
VStack,
Text,
} from '@chakra-ui/react'
import { Food } from 'foods'
import { RefObject } from 'react'
import useSubmitFoodForm from './useSubmitFoodForm'
import { StatFormField } from 'stats'
import Footer from './Footer'
import Header from './Header'
import Tabs from './Tabs'
import useTabs from './useTabs'
type Props = {
onClose: () => void
title: string
nameInputRef: RefObject
food?: Food
canEdit: boolean
isEditing: boolean
onToggleEdit: () => void
onDelete: () => void
onFoodCreatedOrUpdated?: (newFood: Food, oldFood?: Food) => void
}
function Form({
onClose,
nameInputRef,
title,
food,
canEdit,
onFoodCreatedOrUpdated,
isEditing,
onToggleEdit,
onDelete,
}: Props) {
const { onSubmit } = useSubmitFoodForm({
onComplete: (newOrUpdatedFood: Food) => {
onFoodCreatedOrUpdated && onFoodCreatedOrUpdated(newOrUpdatedFood, food)
onClose()
},
})
const { tabNames, onTabNameChange, selectedTabName } = useTabs({
isEditing,
food,
})
return (
)
}
export type { Props }
export default Form
================================================
FILE: src/foods/FoodModal/Content/Form/useSubmitFoodForm.ts
================================================
import { objectFromNutritionDataKeys } from 'stats'
import { Food, FoodForm } from 'foods'
import { useOneTimeCheckActions } from 'general'
import { useFormContext } from 'react-hook-form'
import { useFoodsActions } from 'foods'
import { v4 as uuidv4 } from 'uuid'
type Params = {
onComplete: (food: Food) => void
}
function withProtocol(url: string) {
return !/^https?:\/\//i.test(url) ? `http://${url}` : url
}
function useSubmitFoodForm({ onComplete }: Params) {
const { handleSubmit } = useFormContext()
const foodsActions = useFoodsActions()
const oneTimeCheckActions = useOneTimeCheckActions()
const onSubmit = handleSubmit((foodForm: FoodForm) => {
const food: Food = {
id: foodForm.id !== undefined ? foodForm.id : uuidv4(),
name: foodForm.name,
categoryId: foodForm.categoryId,
addedByUser: true,
servingSizeInGrams: Number(foodForm.servingSizeInGrams),
url: foodForm.url ? withProtocol(foodForm.url) : undefined,
...objectFromNutritionDataKeys(key => Number(foodForm[key])),
}
const { volumeForm } = foodForm
const volumeWeightInGrams = Number(volumeForm.weightInGrams)
if (volumeWeightInGrams > 0) {
food.volume = {
portionId: volumeForm.portionId,
weightInGrams: volumeWeightInGrams,
}
}
if (foodForm.id === undefined) {
oneTimeCheckActions.set(`food-appear-${food.id}`)
}
oneTimeCheckActions.set(`food-flash-${food.id}`)
foodsActions.setFoods([food])
onComplete(food)
})
return {
onSubmit,
}
}
export default useSubmitFoodForm
================================================
FILE: src/foods/FoodModal/Content/Form/useTabs.tsx
================================================
import { Food } from 'foods'
import { useEffect, useState } from 'react'
import { TabName } from './Tabs'
type Params = {
food?: Food
isEditing: boolean
}
function getTabNames(isEditing: boolean, food?: Food): TabName[] {
if (isEditing) {
return ['nutrition', 'volume', 'link']
}
const result: TabName[] = ['nutrition']
if (food?.volume) {
result.push('volume')
}
if (food?.url) {
result.push('link')
}
return result
}
function useTabs({ food, isEditing }: Params) {
const [selectedTabName, setSelectedTabName] = useState('nutrition')
function onTabNameChange(newTabName: TabName) {
setSelectedTabName(newTabName)
}
const tabNames = getTabNames(isEditing, food)
useEffect(() => {
if (!tabNames.includes(selectedTabName)) {
setSelectedTabName('nutrition')
}
}, [food, isEditing, selectedTabName, tabNames])
return {
onTabNameChange,
selectedTabName,
tabNames,
}
}
export default useTabs
================================================
FILE: src/foods/FoodModal/Content/index.tsx
================================================
import { Food } from 'foods'
import { RefObject, useState } from 'react'
import DeleteConfirmationModal from './DeleteConfirmationModal'
import useDeleteFood from './useDeleteFood'
import Form from './Form'
import FoodFormProvider from './FoodFormProvider'
type Props = {
onClose: () => void
title: string
nameInputRef: RefObject
food?: Food
onFoodCreatedOrUpdated?: (newFood: Food, oldFood?: Food) => void
onFoodDeleted?: (food: Food) => void
}
function Content({
onClose,
nameInputRef,
title,
food,
onFoodCreatedOrUpdated,
onFoodDeleted,
}: Props) {
const canEdit = Boolean(food && food.addedByUser)
const deleteFood = useDeleteFood({ food, onClose, onFoodDeleted })
const [isEditing, setIsEditing] = useState(!food)
function onToggleEdit() {
setIsEditing(!isEditing)
}
return (
)
}
export type { Props }
export default Content
================================================
FILE: src/foods/FoodModal/Content/useDeleteFood.ts
================================================
import { useDisclosure } from '@chakra-ui/hooks'
import { useFoodsActions } from 'foods'
import { Food } from 'foods'
import { useToast } from '@chakra-ui/react'
type Params = {
food?: Food
onClose: () => void
onFoodDeleted?: (food: Food) => void
}
function useDeleteFood({ food, onClose, onFoodDeleted }: Params) {
const deleteConfirmationDisclosure = useDisclosure()
const foodsActions = useFoodsActions()
const toast = useToast()
function onDelete() {
deleteConfirmationDisclosure.onOpen()
}
function onConfirmDelete() {
if (food) {
foodsActions.removeFood(food.id)
toast({
position: 'top',
title: 'Food deleted',
status: 'success',
duration: 2000,
isClosable: true,
})
deleteConfirmationDisclosure.onClose()
onFoodDeleted && onFoodDeleted(food)
onClose()
}
}
return {
deleteConfirmationDisclosure,
onDelete,
onConfirmDelete,
}
}
export default useDeleteFood
================================================
FILE: src/foods/FoodModal/index.tsx
================================================
import { Modal, ModalOverlay } from '@chakra-ui/react'
import { Food } from 'foods'
import { useRef } from 'react'
import Content from './Content'
type Props = {
onClose: () => void
isOpen: boolean
food?: Food
onFoodCreatedOrUpdated?: (newFood: Food, oldFood?: Food) => void
onFoodDeleted?: (food: Food) => void
}
function FoodModal({
onClose,
isOpen,
food,
onFoodCreatedOrUpdated,
onFoodDeleted,
}: Props) {
const nameInputRef = useRef(null)
const title = food ? 'Food Details' : 'Create Food'
return (
)
}
export type { Props }
export default FoodModal
================================================
FILE: src/foods/FoodsDrawer/Content/Header.tsx
================================================
import { DrawerHeader, Text } from '@chakra-ui/react'
import { MealForm } from 'meals'
type Props = {
mealName?: string
canSelect: boolean
mealForm?: MealForm
}
function getTitlePrefix(props: Props) {
const { mealName, canSelect, mealForm } = props
if (!mealForm && mealName) {
return 'Select Foods for '
}
if (canSelect) {
return mealName ? 'Add Foods to ' : 'Add Foods'
}
return 'Foods'
}
function Header(props: Props) {
const { mealName } = props
const fontWeight = mealName ? 'normal' : 'bold'
let titlePrefix = getTitlePrefix(props)
return (
{titlePrefix}
{mealName && (
{mealName}
)}
)
}
export default Header
================================================
FILE: src/foods/FoodsDrawer/Content/MenuButtons.tsx
================================================
import { chakra, IconButton } from '@chakra-ui/react'
import { MoreHorizontal, Download, Share } from 'react-feather'
import { Menu, MenuItem } from 'general'
const DownloadStyled = chakra(Download)
const ShareStyled = chakra(Share)
const MoreHorizontalStyled = chakra(MoreHorizontal)
type Props = {
onImport: () => void
onExport: () => void
}
function MenuButtons({ onImport, onExport }: Props) {
return (
}
variant="outline"
/>
}
>
)
}
export default MenuButtons
================================================
FILE: src/foods/FoodsDrawer/Content/SelectedFoodsList/SelectedFoodItem.tsx
================================================
import { Tag, TagLabel, TagCloseButton, Fade } from '@chakra-ui/react'
import { Food } from 'foods'
type Props = {
food: Food
onUnselect: (food: Food) => void
}
function SelectedFoodItem({ food, onUnselect }: Props) {
return (
{food.name}
onUnselect(food)} />
)
}
export default SelectedFoodItem
================================================
FILE: src/foods/FoodsDrawer/Content/SelectedFoodsList/index.tsx
================================================
import { Flex, Text, Wrap } from '@chakra-ui/react'
import { Selection } from 'general'
import SelectedFoodItem from './SelectedFoodItem'
import { Food, useFoods } from 'foods'
type Props = {
selection: Selection
}
function SelectedFoods({ selection }: Props) {
const { selectedItems: selectedFoods } = selection
const { foodsById } = useFoods()
return (
{selectedFoods.length > 0 ? (
{selectedFoods.map(({ id }) => (
))}
) : (
Select one or more foods
)}
)
}
export default SelectedFoods
================================================
FILE: src/foods/FoodsDrawer/Content/index.tsx
================================================
import {
DrawerContent,
DrawerCloseButton,
DrawerBody,
DrawerFooter,
Flex,
Button,
VStack,
Text,
HStack,
useDisclosure,
} from '@chakra-ui/react'
import { RefObject, useRef, useState } from 'react'
import { FoodsList, FoodsListMethods, FoodModal, Food } from 'foods'
import { useSelection, Tooltip } from 'general'
import SelectedFoodsList from './SelectedFoodsList'
import Header from './Header'
import MenuButtons from './MenuButtons'
import { useImportFoods, FoodsListModal } from 'foods/persistence'
import { FoodsFilterStoreProvider } from 'foods-filters'
import { loadFoodsFilter } from 'foods-filters/persistence'
import useFoodEvents from './useFoodEvents'
import { MealForm } from 'meals'
type Props = {
onClose: () => void
mealName?: string
mealForm?: MealForm
searchInputRef: RefObject
onSelectedFoods?: (foods: Food[], mealName?: string) => void
canSelect: boolean
}
function Content({
onClose,
mealName,
mealForm,
searchInputRef,
onSelectedFoods,
canSelect,
}: Props) {
const selection = useSelection()
const listRef = useRef(null)
const foodEvents = useFoodEvents({ listRef, selection })
const foodsListModalDisclosure = useDisclosure()
const importFoods = useImportFoods({ foodsListModalDisclosure })
const [foodsFilter] = useState(loadFoodsFilter)
function onAdd() {
onSelectedFoods && onSelectedFoods(selection.selectedItems, mealName)
}
return (
Need more foods?
{canSelect && }
{!canSelect && (
)}
{canSelect && (
)}
)
}
export default Content
================================================
FILE: src/foods/FoodsDrawer/Content/useFoodEvents.ts
================================================
import { useDisclosure } from '@chakra-ui/react'
import { Food } from 'foods'
import { useState, RefObject } from 'react'
import { FoodsListMethods } from 'foods'
import { Selection } from 'general'
type Params = {
listRef: RefObject
selection: Selection
}
function useFoodEvents({ listRef, selection }: Params) {
const foodModalDisclosure = useDisclosure()
const [food, setFood] = useState()
function onCreateFood() {
setFood(undefined)
foodModalDisclosure.onOpen()
}
function onPreviewFood(food: Food) {
setFood(food)
foodModalDisclosure.onOpen()
}
function onFoodDeleted(food: Food) {
selection.removeItem(food)
}
function onFoodCreatedOrUpdated(newFood: Food, oldFood?: Food) {
if (!listRef.current) {
return
}
if (!oldFood || (oldFood && newFood.categoryId !== oldFood.categoryId)) {
listRef.current.scrollToFood(newFood)
}
}
return {
onCreateFood,
onPreviewFood,
onFoodCreatedOrUpdated,
food,
foodModalDisclosure,
onFoodDeleted,
}
}
export default useFoodEvents
================================================
FILE: src/foods/FoodsDrawer/index.tsx
================================================
import { Drawer, DrawerOverlay } from '@chakra-ui/react'
import { Food } from 'foods'
import { MealForm } from 'meals'
import { useRef } from 'react'
import { isMobile } from 'react-device-detect'
import Content from './Content'
type Props = {
onClose: () => void
isOpen: boolean
mealName?: string
mealForm?: MealForm
canSelect?: boolean
onSelectedFoods?: (foods: Food[], mealName?: string) => void
}
function FoodsDrawer({
onClose,
isOpen,
mealName,
mealForm,
canSelect = true,
onSelectedFoods,
}: Props) {
const searchInputRef = useRef(null)
return (
)
}
export default FoodsDrawer
================================================
FILE: src/foods/FoodsList/VirtualizedList/FoodItem/AnimateAppear.tsx
================================================
import { motion } from 'framer-motion'
import { ReactNode } from 'react'
type Props = {
shouldAnimate: boolean
children: ReactNode
}
const variants = {
open: {
opacity: 1,
scale: 1,
},
hidden: { opacity: 0, scale: 0.9 },
}
function AnimateAppear({ shouldAnimate, children }: Props) {
return (
{children}
)
}
export default AnimateAppear
================================================
FILE: src/foods/FoodsList/VirtualizedList/FoodItem/DisappearingBox.tsx
================================================
import { Box } from '@chakra-ui/react'
import { useEffect, useState } from 'react'
type Props = {
shouldAnimate: boolean
}
function DisappearingBox({ shouldAnimate }: Props) {
const [opacity, setOpacity] = useState(shouldAnimate ? 1 : 0)
useEffect(() => {
if (shouldAnimate) {
setOpacity(0)
}
}, [shouldAnimate])
return (
)
}
export default DisappearingBox
================================================
FILE: src/foods/FoodsList/VirtualizedList/FoodItem/index.tsx
================================================
import { FoodInfo, Food } from 'foods'
import { Flex, FlexProps, Box, chakra, IconButton } from '@chakra-ui/react'
import { Info } from 'react-feather'
import { MouseEvent } from 'react'
import { useOneTimeCheckActions, Tooltip } from 'general'
import DisappearingBox from './DisappearingBox'
import AnimateAppear from './AnimateAppear'
const InfoStyled = chakra(Info)
type UsageType = 'selectOrPreview' | 'previewOnly' | 'nonInteractive'
type Props = {
food: Food
isSelected?: boolean
onPreview: (food: Food) => void
onChoose: (food: Food) => void
usageType?: UsageType
} & FlexProps
function FoodItem({
food,
isSelected = false,
onPreview,
onChoose,
usageType = 'selectOrPreview',
...rest
}: Props) {
function onInfoButtonClick(event: MouseEvent) {
event.stopPropagation()
onPreview(food)
}
const oneTimeCheckActions = useOneTimeCheckActions()
const shouldAnimateAppear = oneTimeCheckActions.checkAndReset(
`food-appear-${food.id}`
)
const shouldAnimateFlash = oneTimeCheckActions.checkAndReset(
`food-flash-${food.id}`
)
return (
{
if (usageType === 'previewOnly') {
onPreview(food)
} else if (usageType === 'selectOrPreview') {
onChoose(food)
}
}}
{...rest}
>
{shouldAnimateFlash && (
)}
{usageType === 'selectOrPreview' && (
}
variant="ghost"
onClick={onInfoButtonClick}
position="relative"
zIndex={1}
/>
)}
)
}
export type { UsageType }
export default FoodItem
================================================
FILE: src/foods/FoodsList/VirtualizedList/FoodItemRenderer.tsx
================================================
import { Food } from 'foods'
import FoodItem, { UsageType } from './FoodItem'
import { TOP_PADDING } from './Inner'
type Data = {
getFood: (index: number) => Food
isFoodSelected: (food: Food) => boolean
onFoodSelect: (food: Food) => void
onFoodPreview: (food: Food) => void
usageType: UsageType
}
type Props = {
style: any
index: number
data: Data
}
function FoodItemRenderer({ style, index, data }: Props) {
const {
getFood,
onFoodSelect,
onFoodPreview,
isFoodSelected,
usageType,
} = data
const food = getFood(index)
return (
)
}
export default FoodItemRenderer
================================================
FILE: src/foods/FoodsList/VirtualizedList/Inner.tsx
================================================
import { forwardRef } from 'react'
const TOP_PADDING = 12
const Inner = forwardRef(({ style, ...rest }, ref) => (
))
export { TOP_PADDING }
export default Inner
================================================
FILE: src/foods/FoodsList/VirtualizedList/index.tsx
================================================
import { Box } from '@chakra-ui/react'
import { FixedSizeList } from 'react-window'
import { forwardRef, ForwardedRef } from 'react'
import { Food } from 'foods'
import Inner from './Inner'
import FoodItemRenderer from './FoodItemRenderer'
import { UsageType } from './FoodItem'
import { useElementHeight } from 'general'
type Props = {
foodsCount: number
getFood: (index: number) => Food
isFoodSelected: (food: Food) => boolean
onFoodSelect: (food: Food) => void
onFoodPreview: (food: Food) => void
forwardRef?: ForwardedRef
itemUsageType: UsageType
}
function VirtualizedList({
getFood,
isFoodSelected,
onFoodSelect,
onFoodPreview,
foodsCount,
forwardRef,
itemUsageType,
}: Props) {
const { elementHeight, elementRef } = useElementHeight()
return (
{FoodItemRenderer}
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/foods/FoodsList/index.tsx
================================================
import {
Input,
InputGroup,
InputLeftElement,
chakra,
Flex,
Text,
FlexProps,
HStack,
Box,
} from '@chakra-ui/react'
import { Divider } from '@chakra-ui/react'
import { Search } from 'react-feather'
import VirtualizedList from './VirtualizedList'
import { Selection } from 'general'
import {
ForwardedRef,
RefObject,
useRef,
useImperativeHandle,
forwardRef,
ChangeEvent,
useEffect,
} from 'react'
import { useFoods } from 'foods'
import {
useFilterFoods,
useFoodsFilter,
useFoodsFilterActions,
} from 'foods-filters'
import { Food } from 'foods'
import { FixedSizeList } from 'react-window'
import { FoodsFilterPopoverOrModal } from 'foods-filters'
import { UsageType } from './VirtualizedList/FoodItem'
import { isMobile } from 'react-device-detect'
const SearchStyled = chakra(Search)
type FoodsListMethods = {
scrollToFood: (food: Food) => void
}
type Props = {
searchInputRef?: RefObject
selection?: Selection
onFoodPreview?: (food: Food) => void
forwardedRef?: ForwardedRef
allowsFiltering?: boolean
itemUsageType?: UsageType
} & FlexProps
function FoodsList({
selection,
searchInputRef,
onFoodPreview,
forwardedRef,
allowsFiltering = true,
itemUsageType = 'selectOrPreview',
...rest
}: Props) {
const { allFoods, userFoods } = useFoods()
const listRef = useRef(null)
const filter = useFoodsFilter()
const foodsFilterActions = useFoodsFilterActions()
const filteredFoods = useFilterFoods(allFoods, userFoods, filter)
useEffect(() => {
if (filter.categoryId) {
listRef.current?.scrollToItem(0, 'start')
}
}, [filter.categoryId])
useImperativeHandle(forwardedRef, () => ({
scrollToFood: (food: Food) => {
foodsFilterActions.resetCategoryIdAndQuery()
if (listRef.current) {
const foods = filter.onlyFoodsAddedByUser ? userFoods : allFoods
const index = foods.map(({ id }) => id).indexOf(food.id)
listRef.current.scrollToItem(index, 'center')
}
},
}))
function onFoodSelect(food: Food) {
if (selection) {
selection.toggleItem(food)
const input = searchInputRef?.current
if (input && !isMobile) {
input.focus()
input.setSelectionRange(0, input.value.length)
}
}
}
return (
{allowsFiltering && (
)}
}
/>
) =>
foodsFilterActions.updateFilter({ query: event.target.value })
}
placeholder="Search"
/>
{filteredFoods.length > 0 ? (
selection ? selection.isIdSelected(food.id) : false
}
getFood={index => filteredFoods[index]}
onFoodSelect={onFoodSelect}
onFoodPreview={onFoodPreview || (() => {})}
itemUsageType={itemUsageType}
/>
) : (
No foods found
)}
)
}
export type { FoodsListMethods }
export default forwardRef((props, ref) => (
))
================================================
FILE: src/foods/builtIn/bakedProducts.json
================================================
[
{
"id": 3001,
"name": "Taco shells",
"categoryId": 3000,
"energy": 476,
"fat": 21.79,
"saturatedFat": 7.105,
"monounsaturatedFat": 6.935,
"polyunsaturatedFat": 5.495,
"carbs": 63.49,
"sugar": 1.5,
"fiber": 6.7,
"protein": 6.41,
"sodium": 324,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.216,
"vitaminB2": 0.08,
"vitaminB3": 1.867,
"vitaminB5": 0,
"vitaminB6": 0.203,
"vitaminB9": 69,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.69,
"vitaminK": 8.6,
"magnesium": 83,
"calcium": 100,
"phosphorus": 233,
"potassium": 231,
"iron": 1.64,
"selenium": 4.8,
"zinc": 1.61,
"manganese": 0.56,
"copper": 0.113,
"choline": 29.9
},
{
"id": 3002,
"name": "Flour tortilla",
"categoryId": 3000,
"energy": 306,
"fat": 7.99,
"saturatedFat": 2.924,
"monounsaturatedFat": 1.751,
"polyunsaturatedFat": 2.29,
"carbs": 49.38,
"sugar": 3.71,
"fiber": 3.5,
"protein": 8.2,
"sodium": 736,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.503,
"vitaminB2": 0.282,
"vitaminB3": 4.415,
"vitaminB5": 0,
"vitaminB6": 0.059,
"vitaminB9": 94,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 7.2,
"magnesium": 22,
"calcium": 146,
"phosphorus": 206,
"potassium": 125,
"iron": 3.63,
"selenium": 22.3,
"zinc": 0.53,
"manganese": 0,
"copper": 0.104,
"choline": 7.9
},
{
"id": 3003,
"name": "Corn tortilla",
"categoryId": 3000,
"energy": 218,
"fat": 2.85,
"saturatedFat": 0.453,
"monounsaturatedFat": 0.692,
"polyunsaturatedFat": 1.419,
"carbs": 44.64,
"sugar": 0.88,
"fiber": 6.3,
"protein": 5.7,
"sodium": 45,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.094,
"vitaminB2": 0.065,
"vitaminB3": 1.498,
"vitaminB5": 0,
"vitaminB6": 0.219,
"vitaminB9": 5,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.28,
"vitaminK": 0,
"magnesium": 72,
"calcium": 81,
"phosphorus": 314,
"potassium": 186,
"iron": 1.23,
"selenium": 6.1,
"zinc": 1.31,
"manganese": 0,
"copper": 0.154,
"choline": 13.3
},
{
"id": 3004,
"name": "Bagel",
"categoryId": 3000,
"energy": 264,
"fat": 1.32,
"saturatedFat": 0.36,
"monounsaturatedFat": 0.39,
"polyunsaturatedFat": 0.526,
"carbs": 52.38,
"sugar": 8.43,
"fiber": 1.6,
"protein": 10.56,
"sodium": 422,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.568,
"vitaminB2": 0.344,
"vitaminB3": 4.515,
"vitaminB5": 0,
"vitaminB6": 0.07,
"vitaminB9": 106,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.1,
"vitaminK": 0.2,
"magnesium": 29,
"calcium": 105,
"phosphorus": 99,
"potassium": 107,
"iron": 3.57,
"selenium": 21.5,
"zinc": 0.83,
"manganese": 0,
"copper": 0.128,
"choline": 14.6
},
{
"id": 3005,
"name": "Whole-grain bread",
"categoryId": 3000,
"energy": 265,
"fat": 4.23,
"saturatedFat": 0.872,
"monounsaturatedFat": 0.76,
"polyunsaturatedFat": 1.872,
"carbs": 43.34,
"sugar": 6.39,
"fiber": 7.4,
"protein": 13.36,
"sodium": 381,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.279,
"vitaminB2": 0.131,
"vitaminB3": 4.042,
"vitaminB5": 0.336,
"vitaminB6": 0.263,
"vitaminB9": 75,
"vitaminB12": 0,
"vitaminC": 0.1,
"vitaminD": 0,
"vitaminE": 0.37,
"vitaminK": 1.4,
"magnesium": 78,
"calcium": 103,
"phosphorus": 228,
"potassium": 230,
"iron": 2.5,
"selenium": 32.9,
"zinc": 1.7,
"manganese": 2.025,
"copper": 0.282,
"choline": 22
},
{
"id": 3006,
"name": "White bread",
"categoryId": 3000,
"energy": 270,
"fat": 3.59,
"saturatedFat": 0.821,
"monounsaturatedFat": 0.717,
"polyunsaturatedFat": 1.87,
"carbs": 49.2,
"sugar": 5.34,
"fiber": 2.3,
"protein": 9.43,
"sodium": 477,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.507,
"vitaminB2": 0.24,
"vitaminB3": 4.76,
"vitaminB5": 0,
"vitaminB6": 0.092,
"vitaminB9": 111,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.22,
"vitaminK": 0.2,
"magnesium": 27,
"calcium": 211,
"phosphorus": 113,
"potassium": 117,
"iron": 3.36,
"selenium": 23.2,
"zinc": 0.88,
"manganese": 0,
"copper": 0.124,
"choline": 14.6
},
{
"id": 3007,
"name": "Jumbo Seeded Hamburger Buns",
"categoryId": 3000,
"energy": 277,
"fat": 4.62,
"saturatedFat": 0.77,
"monounsaturatedFat": 0.77,
"polyunsaturatedFat": 1.54,
"carbs": 50.77,
"sugar": 4.62,
"fiber": 1.5,
"protein": 9.23,
"sodium": 446,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0.308,
"vitaminB3": 4.154,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 92,
"phosphorus": 0,
"potassium": 92,
"iron": 3.08,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"url": "https://www.instacart.com/products/18368481-holsum-cotton-s-jumbo-seeded-hamburger-buns-18-2-oz"
},
{
"id": 3008,
"name": "While-wheat pita",
"categoryId": 3000,
"energy": 262,
"fat": 1.71,
"saturatedFat": 0.208,
"monounsaturatedFat": 0.349,
"polyunsaturatedFat": 1.055,
"carbs": 55.89,
"sugar": 2.87,
"fiber": 6.1,
"protein": 9.8,
"sodium": 421,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.339,
"vitaminB2": 0.08,
"vitaminB3": 2.84,
"vitaminB5": 0.831,
"vitaminB6": 0.265,
"vitaminB9": 35,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.61,
"vitaminK": 1.4,
"magnesium": 69,
"calcium": 15,
"phosphorus": 180,
"potassium": 170,
"iron": 3.06,
"selenium": 44,
"zinc": 1.52,
"manganese": 1.74,
"copper": 0.29,
"choline": 26.5
},
{
"id": 3009,
"name": "Saltine crakers",
"categoryId": 3000,
"energy": 418,
"fat": 8.64,
"saturatedFat": 1.653,
"monounsaturatedFat": 1.986,
"polyunsaturatedFat": 4.835,
"carbs": 74.05,
"sugar": 1.29,
"fiber": 2.8,
"protein": 9.46,
"sodium": 941,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.702,
"vitaminB2": 0.487,
"vitaminB3": 6.442,
"vitaminB5": 0.536,
"vitaminB6": 0.086,
"vitaminB9": 134,
"vitaminB12": 0.09,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 1.15,
"vitaminK": 25.4,
"magnesium": 23,
"calcium": 19,
"phosphorus": 102,
"potassium": 152,
"iron": 5.57,
"selenium": 10.3,
"zinc": 0.69,
"manganese": 0.686,
"copper": 0.139,
"choline": 16.7,
"volume": {
"portionId": "cups",
"weightInGrams": 45
}
},
{
"id": 3010,
"name": "Snyders' Olde Tyme Pretzels",
"categoryId": 3000,
"energy": 400,
"fat": 3.33,
"saturatedFat": 0,
"monounsaturatedFat": 3.33,
"polyunsaturatedFat": 0,
"carbs": 80,
"sugar": 3.33,
"fiber": 3.3,
"protein": 10,
"sodium": 400,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0.453,
"vitaminB3": 5.333,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 3.6,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"url": "https://www.snydersofhanover.com/olde-tyme"
},
{
"id": 3011,
"name": "Seasoned breadcrumbs",
"categoryId": 3000,
"energy": 383,
"fat": 5.48,
"saturatedFat": 1.391,
"monounsaturatedFat": 1.168,
"polyunsaturatedFat": 2.3,
"carbs": 68.49,
"sugar": 5.74,
"fiber": 4.9,
"protein": 14.13,
"sodium": 2100,
"cholesterol": 1,
"vitaminA": 10,
"vitaminB1": 0.961,
"vitaminB2": 0.415,
"vitaminB3": 6.161,
"vitaminB5": 0.623,
"vitaminB6": 0.171,
"vitaminB9": 119,
"vitaminB12": 0.35,
"vitaminC": 2.7,
"vitaminD": 0,
"vitaminE": 0.26,
"vitaminK": 46,
"magnesium": 46,
"calcium": 182,
"phosphorus": 177,
"potassium": 231,
"iron": 4.92,
"selenium": 24.7,
"zinc": 1.43,
"manganese": 0.984,
"copper": 0.244,
"choline": 14.6,
"volume": {
"portionId": "cups",
"weightInGrams": 120
}
},
{
"id": 3012,
"name": "English muffins",
"categoryId": 3000,
"energy": 245,
"fat": 1.75,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 50.17,
"sugar": 1.75,
"fiber": 3.5,
"protein": 7.02,
"sodium": 386,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.263,
"vitaminB2": 0.179,
"vitaminB3": 2.105,
"vitaminB5": 0,
"vitaminB6": 0.056,
"vitaminB9": 70,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.25,
"vitaminK": 2.3,
"magnesium": 33,
"calcium": 140,
"phosphorus": 127,
"potassium": 130,
"iron": 2.53,
"selenium": 17.3,
"zinc": 0.97,
"manganese": 0,
"copper": 0.164,
"choline": 6.5
},
{
"id": 3013,
"name": "High fiber tortilla",
"categoryId": 3000,
"energy": 111,
"fat": 3.33,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 35.56,
"sugar": 0,
"fiber": 24.4,
"protein": 8.89,
"sodium": 689,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 222,
"phosphorus": 0,
"potassium": 0,
"iron": 1.6,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
},
{
"id": 3014,
"name": "La Tortilla Low carb tortillas",
"categoryId": 3000,
"energy": 167,
"fat": 5.95,
"saturatedFat": 2.38,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 35.71,
"sugar": 2.38,
"fiber": 21.4,
"protein": 11.9,
"sodium": 595,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 102,
"phosphorus": 0,
"potassium": 43,
"iron": 2.38,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"url": "https://www.latortillafactory.com/product/non-gmo-low-carb-flour-soft-taco-size/"
},
{
"id": 3015,
"name": "Wheat crackers",
"categoryId": 3000,
"energy": 455,
"fat": 16.4,
"saturatedFat": 3.21,
"monounsaturatedFat": 3.47,
"polyunsaturatedFat": 8.474,
"carbs": 70.73,
"sugar": 15.48,
"fiber": 6.9,
"protein": 7.3,
"sodium": 699,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.284,
"vitaminB2": 0.146,
"vitaminB3": 4.022,
"vitaminB5": 0.577,
"vitaminB6": 0.244,
"vitaminB9": 38,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 1.55,
"vitaminK": 14.2,
"magnesium": 72,
"calcium": 92,
"phosphorus": 302,
"potassium": 283,
"iron": 2.64,
"selenium": 9.9,
"zinc": 1.64,
"manganese": 1.549,
"copper": 0.274,
"choline": 27.2
},
{
"id": 3016,
"name": "Graham crackers",
"categoryId": 3000,
"energy": 430,
"fat": 10.6,
"saturatedFat": 1.633,
"monounsaturatedFat": 2.509,
"polyunsaturatedFat": 5.388,
"carbs": 77.66,
"sugar": 24.85,
"fiber": 3.4,
"protein": 6.69,
"sodium": 516,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.265,
"vitaminB2": 0.317,
"vitaminB3": 4.439,
"vitaminB5": 0,
"vitaminB6": 0.156,
"vitaminB9": 91,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 1.51,
"vitaminK": 14.3,
"magnesium": 40,
"calcium": 77,
"phosphorus": 185,
"potassium": 170,
"iron": 3.78,
"selenium": 6.3,
"zinc": 0.96,
"manganese": 0,
"copper": 0.17,
"choline": 5.9
}
]
================================================
FILE: src/foods/builtIn/beef.json
================================================
[
{
"id": 201,
"name": "70% Lean Ground Beef",
"categoryId": 200,
"energy": 332,
"fat": 30,
"saturatedFat": 11.754,
"monounsaturatedFat": 14.171,
"polyunsaturatedFat": 0.697,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 14.35,
"sodium": 66,
"cholesterol": 78,
"vitaminA": 4,
"vitaminB1": 0.044,
"vitaminB2": 0.151,
"vitaminB3": 3.382,
"vitaminB5": 0.395,
"vitaminB6": 0.278,
"vitaminB9": 9,
"vitaminB12": 2.07,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.17,
"vitaminK": 2.9,
"magnesium": 14,
"calcium": 24,
"phosphorus": 132,
"potassium": 218,
"iron": 1.64,
"selenium": 13.5,
"zinc": 3.57,
"manganese": 0.009,
"copper": 0.05,
"choline": 46.8
},
{
"id": 202,
"name": "75% Lean Ground Beef",
"categoryId": 200,
"energy": 293,
"fat": 25,
"saturatedFat": 9.568,
"monounsaturatedFat": 11.383,
"polyunsaturatedFat": 0.609,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 15.76,
"sodium": 66,
"cholesterol": 75,
"vitaminA": 4,
"vitaminB1": 0.044,
"vitaminB2": 0.151,
"vitaminB3": 3.804,
"vitaminB5": 0.446,
"vitaminB6": 0.301,
"vitaminB9": 8,
"vitaminB12": 2.11,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.17,
"vitaminK": 2.4,
"magnesium": 15,
"calcium": 21,
"phosphorus": 145,
"potassium": 244,
"iron": 1.79,
"selenium": 14.3,
"zinc": 3.87,
"manganese": 0.009,
"copper": 0.056,
"choline": 51.6
},
{
"id": 203,
"name": "80% Lean Ground Beef",
"categoryId": 200,
"energy": 254,
"fat": 20,
"saturatedFat": 7.581,
"monounsaturatedFat": 8.848,
"polyunsaturatedFat": 0.521,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 17.17,
"sodium": 66,
"cholesterol": 71,
"vitaminA": 4,
"vitaminB1": 0.043,
"vitaminB2": 0.151,
"vitaminB3": 4.227,
"vitaminB5": 0.498,
"vitaminB6": 0.323,
"vitaminB9": 7,
"vitaminB12": 2.14,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.17,
"vitaminK": 1.8,
"magnesium": 17,
"calcium": 18,
"phosphorus": 158,
"potassium": 270,
"iron": 1.94,
"selenium": 15,
"zinc": 4.18,
"manganese": 0.01,
"copper": 0.061,
"choline": 56.4
},
{
"id": 204,
"name": "90% Lean Ground Beef",
"categoryId": 200,
"energy": 176,
"fat": 10,
"saturatedFat": 3.927,
"monounsaturatedFat": 4.194,
"polyunsaturatedFat": 0.345,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 20,
"sodium": 66,
"cholesterol": 65,
"vitaminA": 4,
"vitaminB1": 0.042,
"vitaminB2": 0.151,
"vitaminB3": 5.072,
"vitaminB5": 0.601,
"vitaminB6": 0.369,
"vitaminB9": 6,
"vitaminB12": 2.21,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.17,
"vitaminK": 0.8,
"magnesium": 20,
"calcium": 12,
"phosphorus": 184,
"potassium": 321,
"iron": 2.24,
"selenium": 16.6,
"zinc": 4.79,
"manganese": 0.01,
"copper": 0.072,
"choline": 66.1
},
{
"id": 205,
"name": "95% Lean Ground Beef",
"categoryId": 200,
"energy": 137,
"fat": 5,
"saturatedFat": 2.182,
"monounsaturatedFat": 1.994,
"polyunsaturatedFat": 0.257,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 21.41,
"sodium": 66,
"cholesterol": 62,
"vitaminA": 4,
"vitaminB1": 0.041,
"vitaminB2": 0.151,
"vitaminB3": 5.494,
"vitaminB5": 0.652,
"vitaminB6": 0.392,
"vitaminB9": 5,
"vitaminB12": 2.24,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.17,
"vitaminK": 0.3,
"magnesium": 22,
"calcium": 9,
"phosphorus": 198,
"potassium": 346,
"iron": 2.38,
"selenium": 17.4,
"zinc": 5.09,
"manganese": 0.01,
"copper": 0.078,
"choline": 70.9
},
{
"id": 206,
"name": "Jack Link's Original Beef Jerky",
"categoryId": 200,
"energy": 278,
"fat": 2.78,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 16.67,
"sugar": 11.11,
"fiber": 0,
"protein": 44.44,
"sodium": 2056,
"cholesterol": 111,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 4,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"url": "https://www.jacklinks.com/shop/original-beef-jerky"
}
]
================================================
FILE: src/foods/builtIn/beverages.json
================================================
[
{
"id": 7001,
"name": "Unsweetened Almond Milk",
"categoryId": 7000,
"energy": 15,
"fat": 0.96,
"saturatedFat": 0.08,
"monounsaturatedFat": 0.59,
"polyunsaturatedFat": 0.24,
"carbs": 1.31,
"sugar": 0.81,
"fiber": 0.2,
"protein": 0.4,
"sodium": 72,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0.01,
"vitaminB3": 0.07,
"vitaminB5": 0.01,
"vitaminB6": 0,
"vitaminB9": 1,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 1,
"vitaminE": 6.33,
"vitaminK": 0,
"magnesium": 6,
"calcium": 184,
"phosphorus": 9,
"potassium": 67,
"iron": 0.28,
"selenium": 0.1,
"zinc": 0.06,
"manganese": 0.04,
"copper": 0.02,
"choline": 3.1,
"volume": {
"portionId": "cups",
"weightInGrams": 262
}
},
{
"id": 7002,
"name": "Unsweetened Rice Milk",
"categoryId": 7000,
"energy": 47,
"fat": 0.97,
"saturatedFat": 0,
"monounsaturatedFat": 0.625,
"polyunsaturatedFat": 0.313,
"carbs": 9.17,
"sugar": 5.28,
"fiber": 0.3,
"protein": 0.28,
"sodium": 39,
"cholesterol": 0,
"vitaminA": 63,
"vitaminB1": 0.027,
"vitaminB2": 0.142,
"vitaminB3": 0.39,
"vitaminB5": 0.146,
"vitaminB6": 0.039,
"vitaminB9": 2,
"vitaminB12": 0.63,
"vitaminC": 0,
"vitaminD": 1,
"vitaminE": 0.47,
"vitaminK": 0.2,
"magnesium": 11,
"calcium": 118,
"phosphorus": 56,
"potassium": 27,
"iron": 0.2,
"selenium": 2.2,
"zinc": 0.13,
"manganese": 0.282,
"copper": 0.037,
"choline": 2.1
},
{
"id": 7003,
"name": "Whey Protein Powder",
"categoryId": 7000,
"energy": 352,
"fat": 1.56,
"saturatedFat": 0.781,
"monounsaturatedFat": 0.158,
"polyunsaturatedFat": 0.299,
"carbs": 6.25,
"sugar": 0,
"fiber": 3.1,
"protein": 78.13,
"sodium": 156,
"cholesterol": 16,
"vitaminA": 0,
"vitaminB1": 0.609,
"vitaminB2": 2.017,
"vitaminB3": 1.136,
"vitaminB5": 5.516,
"vitaminB6": 0.607,
"vitaminB9": 33,
"vitaminB12": 2.45,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 195,
"calcium": 469,
"phosphorus": 1321,
"potassium": 500,
"iron": 1.13,
"selenium": 26.7,
"zinc": 6.18,
"manganese": 0,
"copper": 0.049,
"choline": 224,
"volume": {
"portionId": "cups",
"weightInGrams": 32
}
},
{
"id": 7004,
"name": "Coconut Milk",
"categoryId": 7000,
"energy": 31,
"fat": 2.08,
"saturatedFat": 2.083,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 2.92,
"sugar": 2.5,
"fiber": 0,
"protein": 0.21,
"sodium": 19,
"cholesterol": 0,
"vitaminA": 63,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 1.25,
"vitaminC": 0,
"vitaminD": 1,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 188,
"phosphorus": 0,
"potassium": 19,
"iron": 0.3,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 240
}
},
{
"id": 7005,
"name": "Red Wine",
"categoryId": 7000,
"energy": 85,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 2.61,
"sugar": 0.62,
"fiber": 0,
"protein": 0.07,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.005,
"vitaminB2": 0.031,
"vitaminB3": 0.224,
"vitaminB5": 0.03,
"vitaminB6": 0.057,
"vitaminB9": 1,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0.4,
"magnesium": 12,
"calcium": 8,
"phosphorus": 23,
"potassium": 127,
"iron": 0.46,
"selenium": 0.2,
"zinc": 0.14,
"manganese": 0.132,
"copper": 0.011,
"choline": 5.7
},
{
"id": 7006,
"name": "Beer",
"categoryId": 7000,
"energy": 43,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 3.55,
"sugar": 0,
"fiber": 0,
"protein": 0.46,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.005,
"vitaminB2": 0.025,
"vitaminB3": 0.513,
"vitaminB5": 0.041,
"vitaminB6": 0.046,
"vitaminB9": 6,
"vitaminB12": 0.02,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 6,
"calcium": 4,
"phosphorus": 14,
"potassium": 27,
"iron": 0.02,
"selenium": 0.6,
"zinc": 0.01,
"manganese": 0.008,
"copper": 0.005,
"choline": 10.1
}
]
================================================
FILE: src/foods/builtIn/dairyAndEggs.json
================================================
[
{
"id": 501,
"name": "Skim Milk",
"categoryId": 500,
"energy": 34,
"fat": 0.08,
"saturatedFat": 0.049,
"monounsaturatedFat": 0.017,
"polyunsaturatedFat": 0.006,
"carbs": 4.89,
"sugar": 5.05,
"fiber": 0,
"protein": 3.43,
"sodium": 41,
"cholesterol": 3,
"vitaminA": 64,
"vitaminB1": 0.056,
"vitaminB2": 0.131,
"vitaminB3": 0.118,
"vitaminB5": 0,
"vitaminB6": 0.058,
"vitaminB9": 2,
"vitaminB12": 0.58,
"vitaminC": 0,
"vitaminD": 1.1,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 12,
"calcium": 132,
"phosphorus": 107,
"potassium": 167,
"iron": 0,
"selenium": 2,
"zinc": 0.45,
"manganese": 0,
"copper": 0.002,
"choline": 18.2
},
{
"id": 502,
"name": "Whole Eggs",
"categoryId": 500,
"energy": 143,
"fat": 9.51,
"saturatedFat": 3.126,
"monounsaturatedFat": 3.658,
"polyunsaturatedFat": 1.911,
"carbs": 0.72,
"sugar": 0.37,
"fiber": 0,
"protein": 12.56,
"sodium": 142,
"cholesterol": 372,
"vitaminA": 160,
"vitaminB1": 0.04,
"vitaminB2": 0.457,
"vitaminB3": 0.075,
"vitaminB5": 1.533,
"vitaminB6": 0.17,
"vitaminB9": 47,
"vitaminB12": 0.89,
"vitaminC": 0,
"vitaminD": 2,
"vitaminE": 1.05,
"vitaminK": 0.3,
"magnesium": 12,
"calcium": 56,
"phosphorus": 198,
"potassium": 138,
"iron": 1.75,
"selenium": 30.7,
"zinc": 1.29,
"manganese": 0.028,
"copper": 0.072,
"choline": 293.8,
"volume": {
"portionId": "cups",
"weightInGrams": 243
}
},
{
"id": 503,
"name": "Egg Whites",
"categoryId": 500,
"energy": 52,
"fat": 0.17,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 0.73,
"sugar": 0.71,
"fiber": 0,
"protein": 10.9,
"sodium": 166,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.004,
"vitaminB2": 0.439,
"vitaminB3": 0.105,
"vitaminB5": 0.19,
"vitaminB6": 0.005,
"vitaminB9": 4,
"vitaminB12": 0.09,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 11,
"calcium": 7,
"phosphorus": 15,
"potassium": 163,
"iron": 0.08,
"selenium": 20,
"zinc": 0.03,
"manganese": 0.011,
"copper": 0.023,
"choline": 1.1,
"volume": {
"portionId": "cups",
"weightInGrams": 243
}
},
{
"id": 504,
"name": "Half and Half",
"categoryId": 500,
"energy": 131,
"fat": 11.5,
"saturatedFat": 7.032,
"monounsaturatedFat": 3.32,
"polyunsaturatedFat": 0.554,
"carbs": 4.3,
"sugar": 4.13,
"fiber": 0,
"protein": 3.13,
"sodium": 61,
"cholesterol": 35,
"vitaminA": 97,
"vitaminB1": 0.03,
"vitaminB2": 0.194,
"vitaminB3": 0.109,
"vitaminB5": 0.539,
"vitaminB6": 0.05,
"vitaminB9": 3,
"vitaminB12": 0.19,
"vitaminC": 0.9,
"vitaminD": 0,
"vitaminE": 0.25,
"vitaminK": 1.3,
"magnesium": 10,
"calcium": 107,
"phosphorus": 95,
"potassium": 132,
"iron": 0.05,
"selenium": 3.2,
"zinc": 0.39,
"manganese": 0.005,
"copper": 0.009,
"choline": 18.7,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 15
}
},
{
"id": 505,
"name": "Reduced Fat Cheddar Cheese",
"categoryId": 500,
"energy": 316,
"fat": 20.41,
"saturatedFat": 12.602,
"monounsaturatedFat": 5.304,
"polyunsaturatedFat": 0.893,
"carbs": 2.67,
"sugar": 0.26,
"fiber": 0,
"protein": 27.35,
"sodium": 628,
"cholesterol": 76,
"vitaminA": 145,
"vitaminB1": 0.021,
"vitaminB2": 0.397,
"vitaminB3": 0.145,
"vitaminB5": 0.389,
"vitaminB6": 0.084,
"vitaminB9": 20,
"vitaminB12": 1.41,
"vitaminC": 0,
"vitaminD": 0.3,
"vitaminE": 0.48,
"vitaminK": 1.5,
"magnesium": 27,
"calcium": 761,
"phosphorus": 520,
"potassium": 63,
"iron": 0.12,
"selenium": 35.8,
"zinc": 4.44,
"manganese": 0.031,
"copper": 0.043,
"choline": 15.4
},
{
"id": 506,
"name": "Sour Cream",
"categoryId": 500,
"energy": 198,
"fat": 19.35,
"saturatedFat": 10.14,
"monounsaturatedFat": 4.594,
"polyunsaturatedFat": 0.8,
"carbs": 4.63,
"sugar": 3.41,
"fiber": 0,
"protein": 2.44,
"sodium": 31,
"cholesterol": 59,
"vitaminA": 124,
"vitaminB1": 0.02,
"vitaminB2": 0.168,
"vitaminB3": 0.093,
"vitaminB5": 0.472,
"vitaminB6": 0.041,
"vitaminB9": 6,
"vitaminB12": 0.21,
"vitaminC": 0.9,
"vitaminD": 0,
"vitaminE": 0.38,
"vitaminK": 1.5,
"magnesium": 10,
"calcium": 101,
"phosphorus": 76,
"potassium": 125,
"iron": 0.07,
"selenium": 3.7,
"zinc": 0.33,
"manganese": 0.015,
"copper": 0.018,
"choline": 19.2,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 12
}
},
{
"id": 507,
"name": "Fat Free Sour Cream",
"categoryId": 500,
"energy": 74,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 15.6,
"sugar": 0.39,
"fiber": 0,
"protein": 3.1,
"sodium": 141,
"cholesterol": 9,
"vitaminA": 73,
"vitaminB1": 0.04,
"vitaminB2": 0.15,
"vitaminB3": 0.07,
"vitaminB5": 0,
"vitaminB6": 0.02,
"vitaminB9": 11,
"vitaminB12": 0.3,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 10,
"calcium": 125,
"phosphorus": 95,
"potassium": 129,
"iron": 0,
"selenium": 5.3,
"zinc": 0.5,
"manganese": 0,
"copper": 0.016,
"choline": 19.2,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 12
}
},
{
"id": 508,
"name": "2% Milk",
"categoryId": 500,
"energy": 50,
"fat": 1.98,
"saturatedFat": 1.257,
"monounsaturatedFat": 0.56,
"polyunsaturatedFat": 0.073,
"carbs": 4.8,
"sugar": 5.06,
"fiber": 0,
"protein": 3.3,
"sodium": 47,
"cholesterol": 8,
"vitaminA": 55,
"vitaminB1": 0.039,
"vitaminB2": 0.185,
"vitaminB3": 0.092,
"vitaminB5": 0.356,
"vitaminB6": 0.038,
"vitaminB9": 5,
"vitaminB12": 0.53,
"vitaminC": 0.2,
"vitaminD": 1.2,
"vitaminE": 0.03,
"vitaminK": 0.2,
"magnesium": 11,
"calcium": 120,
"phosphorus": 92,
"potassium": 140,
"iron": 0.02,
"selenium": 2.5,
"zinc": 0.48,
"manganese": 0.014,
"copper": 0.006,
"choline": 16.4,
"volume": {
"portionId": "cups",
"weightInGrams": 244
}
},
{
"id": 509,
"name": "Nonfat Mozzarella Cheese",
"categoryId": 500,
"energy": 141,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 3.5,
"sugar": 1.48,
"fiber": 1.8,
"protein": 31.7,
"sodium": 743,
"cholesterol": 18,
"vitaminA": 127,
"vitaminB1": 0.02,
"vitaminB2": 0.3,
"vitaminB3": 0.12,
"vitaminB5": 0,
"vitaminB6": 0.08,
"vitaminB9": 10,
"vitaminB12": 0.92,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.14,
"vitaminK": 1.6,
"magnesium": 33,
"calcium": 961,
"phosphorus": 656,
"potassium": 106,
"iron": 0.31,
"selenium": 18.9,
"zinc": 3.92,
"manganese": 0,
"copper": 0.034,
"choline": 15.4,
"volume": {
"portionId": "cups",
"weightInGrams": 113
}
},
{
"id": 510,
"name": "Feta Cheese",
"categoryId": 500,
"energy": 265,
"fat": 21.49,
"saturatedFat": 13.3,
"monounsaturatedFat": 4.623,
"polyunsaturatedFat": 0.591,
"carbs": 3.88,
"sugar": 0,
"fiber": 0,
"protein": 14.21,
"sodium": 1139,
"cholesterol": 89,
"vitaminA": 125,
"vitaminB1": 0.154,
"vitaminB2": 0.844,
"vitaminB3": 0.991,
"vitaminB5": 0.967,
"vitaminB6": 0.424,
"vitaminB9": 32,
"vitaminB12": 1.69,
"vitaminC": 0,
"vitaminD": 0.4,
"vitaminE": 0.18,
"vitaminK": 1.8,
"magnesium": 19,
"calcium": 493,
"phosphorus": 337,
"potassium": 62,
"iron": 0.65,
"selenium": 15,
"zinc": 2.88,
"manganese": 0.028,
"copper": 0.032,
"choline": 15.4,
"volume": {
"portionId": "cups",
"weightInGrams": 150
}
},
{
"id": 511,
"name": "0% Greek Yogurt",
"categoryId": 500,
"energy": 53,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 2.94,
"sugar": 2.94,
"fiber": 0,
"protein": 10.59,
"sodium": 38,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 118,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
},
{
"id": 512,
"name": "1% Cottage Cheese",
"categoryId": 500,
"energy": 72,
"fat": 1.02,
"saturatedFat": 0.645,
"monounsaturatedFat": 0.291,
"polyunsaturatedFat": 0.031,
"carbs": 2.72,
"sugar": 2.72,
"fiber": 0,
"protein": 12.39,
"sodium": 406,
"cholesterol": 4,
"vitaminA": 11,
"vitaminB1": 0.021,
"vitaminB2": 0.165,
"vitaminB3": 0.128,
"vitaminB5": 0.215,
"vitaminB6": 0.068,
"vitaminB9": 12,
"vitaminB12": 0.63,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.01,
"vitaminK": 0.1,
"magnesium": 5,
"calcium": 61,
"phosphorus": 134,
"potassium": 86,
"iron": 0.14,
"selenium": 9,
"zinc": 0.38,
"manganese": 0.003,
"copper": 0.028,
"choline": 17.5,
"volume": {
"portionId": "cups",
"weightInGrams": 226
}
},
{
"id": 513,
"name": "2% Cottage Cheese",
"categoryId": 500,
"energy": 81,
"fat": 2.27,
"saturatedFat": 1.235,
"monounsaturatedFat": 0.516,
"polyunsaturatedFat": 0.083,
"carbs": 4.76,
"sugar": 4,
"fiber": 0,
"protein": 10.45,
"sodium": 308,
"cholesterol": 12,
"vitaminA": 68,
"vitaminB1": 0.02,
"vitaminB2": 0.251,
"vitaminB3": 0.103,
"vitaminB5": 0.524,
"vitaminB6": 0.057,
"vitaminB9": 8,
"vitaminB12": 0.47,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.08,
"vitaminK": 0,
"magnesium": 9,
"calcium": 111,
"phosphorus": 150,
"potassium": 125,
"iron": 0.13,
"selenium": 11.9,
"zinc": 0.51,
"manganese": 0.015,
"copper": 0.033,
"choline": 16.3,
"volume": {
"portionId": "cups",
"weightInGrams": 226
}
},
{
"id": 514,
"name": "Grated Parmesan Cheese",
"categoryId": 500,
"energy": 420,
"fat": 27.84,
"saturatedFat": 15.371,
"monounsaturatedFat": 7.13,
"polyunsaturatedFat": 1.386,
"carbs": 13.91,
"sugar": 0.07,
"fiber": 0,
"protein": 28.42,
"sodium": 1804,
"cholesterol": 86,
"vitaminA": 262,
"vitaminB1": 0.026,
"vitaminB2": 0.358,
"vitaminB3": 0.08,
"vitaminB5": 0.45,
"vitaminB6": 0.081,
"vitaminB9": 6,
"vitaminB12": 1.4,
"vitaminC": 0,
"vitaminD": 0.5,
"vitaminE": 0.53,
"vitaminK": 1.7,
"magnesium": 34,
"calcium": 853,
"phosphorus": 627,
"potassium": 180,
"iron": 0.49,
"selenium": 34.4,
"zinc": 4.2,
"manganese": 0.071,
"copper": 0.04,
"choline": 14.1,
"volume": {
"portionId": "cups",
"weightInGrams": 100
}
},
{
"id": 515,
"name": "Light Whipping Cream",
"categoryId": 500,
"energy": 292,
"fat": 30.91,
"saturatedFat": 19.337,
"monounsaturatedFat": 9.093,
"polyunsaturatedFat": 0.884,
"carbs": 2.96,
"sugar": 2.96,
"fiber": 0,
"protein": 2.17,
"sodium": 34,
"cholesterol": 111,
"vitaminA": 279,
"vitaminB1": 0.024,
"vitaminB2": 0.125,
"vitaminB3": 0.042,
"vitaminB5": 0.259,
"vitaminB6": 0.028,
"vitaminB9": 4,
"vitaminB12": 0.2,
"vitaminC": 0.6,
"vitaminD": 0.6,
"vitaminE": 0.88,
"vitaminK": 2.7,
"magnesium": 7,
"calcium": 69,
"phosphorus": 61,
"potassium": 97,
"iron": 0.03,
"selenium": 0.5,
"zinc": 0.25,
"manganese": 0.001,
"copper": 0.007,
"choline": 16.8,
"volume": {
"portionId": "cups",
"weightInGrams": 239
}
},
{
"id": 516,
"name": "Reduced Fat Grated Parmesan Cheese",
"categoryId": 500,
"energy": 265,
"fat": 20,
"saturatedFat": 13.317,
"monounsaturatedFat": 6.098,
"polyunsaturatedFat": 0.462,
"carbs": 1.37,
"sugar": 0,
"fiber": 0,
"protein": 20,
"sodium": 1529,
"cholesterol": 88,
"vitaminA": 160,
"vitaminB1": 0.029,
"vitaminB2": 0.486,
"vitaminB3": 0.114,
"vitaminB5": 0.325,
"vitaminB6": 0.049,
"vitaminB9": 10,
"vitaminB12": 2.26,
"vitaminC": 0,
"vitaminD": 0.4,
"vitaminE": 0.17,
"vitaminK": 1.7,
"magnesium": 38,
"calcium": 1109,
"phosphorus": 729,
"potassium": 125,
"iron": 0.9,
"selenium": 17.7,
"zinc": 3.87,
"manganese": 0.085,
"copper": 0.238,
"choline": 20.7,
"volume": {
"portionId": "cups",
"weightInGrams": 100
}
},
{
"id": 517,
"name": "Neufchatel Cheese",
"categoryId": 500,
"energy": 253,
"fat": 22.78,
"saturatedFat": 12.79,
"monounsaturatedFat": 5.784,
"polyunsaturatedFat": 0.97,
"carbs": 3.59,
"sugar": 3.19,
"fiber": 0,
"protein": 9.15,
"sodium": 334,
"cholesterol": 74,
"vitaminA": 241,
"vitaminB1": 0.022,
"vitaminB2": 0.155,
"vitaminB3": 0.21,
"vitaminB5": 0.575,
"vitaminB6": 0.041,
"vitaminB9": 14,
"vitaminB12": 0.3,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.4,
"vitaminK": 1.7,
"magnesium": 10,
"calcium": 117,
"phosphorus": 138,
"potassium": 152,
"iron": 0.13,
"selenium": 3,
"zinc": 0.82,
"manganese": 0.011,
"copper": 0.027,
"choline": 0
},
{
"id": 518,
"name": "Low Fat Cream Cheese",
"categoryId": 500,
"energy": 208,
"fat": 16.67,
"saturatedFat": 10,
"monounsaturatedFat": 3.996,
"polyunsaturatedFat": 0.575,
"carbs": 6.73,
"sugar": 3.3,
"fiber": 0,
"protein": 7.85,
"sodium": 317,
"cholesterol": 54,
"vitaminA": 161,
"vitaminB1": 0.04,
"vitaminB2": 0.185,
"vitaminB3": 0.125,
"vitaminB5": 0.845,
"vitaminB6": 0.045,
"vitaminB9": 19,
"vitaminB12": 0.92,
"vitaminC": 0,
"vitaminD": 0.3,
"vitaminE": 0.27,
"vitaminK": 1.1,
"magnesium": 8,
"calcium": 148,
"phosphorus": 152,
"potassium": 247,
"iron": 0.17,
"selenium": 4,
"zinc": 0.57,
"manganese": 0.011,
"copper": 0.032,
"choline": 12.1,
"volume": {
"portionId": "cups",
"weightInGrams": 240
}
},
{
"id": 519,
"name": "Fat Free American Cheese",
"categoryId": 500,
"energy": 126,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 10.53,
"sugar": 5.26,
"fiber": 0,
"protein": 21.05,
"sodium": 1316,
"cholesterol": 26,
"vitaminA": 56,
"vitaminB1": 0.412,
"vitaminB2": 0.545,
"vitaminB3": 5.56,
"vitaminB5": 0,
"vitaminB6": 0.567,
"vitaminB9": 9,
"vitaminB12": 1.85,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.27,
"vitaminK": 0.2,
"magnesium": 115,
"calcium": 789,
"phosphorus": 316,
"potassium": 393,
"iron": 0,
"selenium": 14.6,
"zinc": 4.11,
"manganese": 0,
"copper": 0.559,
"choline": 38.4
},
{
"id": 520,
"name": "Cream Cheese",
"categoryId": 500,
"energy": 350,
"fat": 34.44,
"saturatedFat": 20.213,
"monounsaturatedFat": 8.907,
"polyunsaturatedFat": 1.483,
"carbs": 5.52,
"sugar": 3.76,
"fiber": 0,
"protein": 6.15,
"sodium": 314,
"cholesterol": 101,
"vitaminA": 308,
"vitaminB1": 0.023,
"vitaminB2": 0.23,
"vitaminB3": 0.091,
"vitaminB5": 0.517,
"vitaminB6": 0.056,
"vitaminB9": 9,
"vitaminB12": 0.22,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.86,
"vitaminK": 2.1,
"magnesium": 9,
"calcium": 97,
"phosphorus": 107,
"potassium": 132,
"iron": 0.11,
"selenium": 8.6,
"zinc": 0.5,
"manganese": 0.011,
"copper": 0.018,
"choline": 26.8,
"volume": {
"portionId": "cups",
"weightInGrams": 232
}
},
{
"id": 521,
"name": "Gouda Cheese",
"categoryId": 500,
"energy": 356,
"fat": 27.44,
"saturatedFat": 17.614,
"monounsaturatedFat": 7.747,
"polyunsaturatedFat": 0.657,
"carbs": 2.22,
"sugar": 2.22,
"fiber": 0,
"protein": 24.94,
"sodium": 819,
"cholesterol": 114,
"vitaminA": 165,
"vitaminB1": 0.03,
"vitaminB2": 0.334,
"vitaminB3": 0.063,
"vitaminB5": 0.34,
"vitaminB6": 0.08,
"vitaminB9": 21,
"vitaminB12": 1.54,
"vitaminC": 0,
"vitaminD": 0.5,
"vitaminE": 0.24,
"vitaminK": 2.3,
"magnesium": 29,
"calcium": 700,
"phosphorus": 546,
"potassium": 121,
"iron": 0.24,
"selenium": 14.5,
"zinc": 3.9,
"manganese": 0.011,
"copper": 0.036,
"choline": 15.4
},
{
"id": 522,
"name": "Brie Cheese",
"categoryId": 500,
"energy": 334,
"fat": 27.68,
"saturatedFat": 17.41,
"monounsaturatedFat": 8.013,
"polyunsaturatedFat": 0.826,
"carbs": 0.45,
"sugar": 0.45,
"fiber": 0,
"protein": 20.75,
"sodium": 629,
"cholesterol": 100,
"vitaminA": 174,
"vitaminB1": 0.07,
"vitaminB2": 0.52,
"vitaminB3": 0.38,
"vitaminB5": 0.69,
"vitaminB6": 0.235,
"vitaminB9": 65,
"vitaminB12": 1.65,
"vitaminC": 0,
"vitaminD": 0.5,
"vitaminE": 0.24,
"vitaminK": 2.3,
"magnesium": 20,
"calcium": 184,
"phosphorus": 188,
"potassium": 152,
"iron": 0.5,
"selenium": 14.5,
"zinc": 2.38,
"manganese": 0.034,
"copper": 0.019,
"choline": 15.4,
"volume": {
"portionId": "cups",
"weightInGrams": 240
}
},
{
"id": 523,
"name": "Cheddar Cheese",
"categoryId": 500,
"energy": 410,
"fat": 33.82,
"saturatedFat": 19.368,
"monounsaturatedFat": 8.428,
"polyunsaturatedFat": 1.433,
"carbs": 2.13,
"sugar": 0.27,
"fiber": 0,
"protein": 24.25,
"sodium": 644,
"cholesterol": 99,
"vitaminA": 263,
"vitaminB1": 0.027,
"vitaminB2": 0.434,
"vitaminB3": 0.039,
"vitaminB5": 0.481,
"vitaminB6": 0.075,
"vitaminB9": 27,
"vitaminB12": 0.88,
"vitaminC": 0,
"vitaminD": 1,
"vitaminE": 0.78,
"vitaminK": 2.4,
"magnesium": 27,
"calcium": 711,
"phosphorus": 460,
"potassium": 76,
"iron": 0.16,
"selenium": 28.3,
"zinc": 3.74,
"manganese": 0.024,
"copper": 0.035,
"choline": 16.5
},
{
"id": 524,
"name": "Blue Cheese",
"categoryId": 500,
"energy": 353,
"fat": 28.74,
"saturatedFat": 18.669,
"monounsaturatedFat": 7.778,
"polyunsaturatedFat": 0.8,
"carbs": 2.34,
"sugar": 0.5,
"fiber": 0,
"protein": 21.4,
"sodium": 1146,
"cholesterol": 75,
"vitaminA": 198,
"vitaminB1": 0.029,
"vitaminB2": 0.382,
"vitaminB3": 1.016,
"vitaminB5": 1.729,
"vitaminB6": 0.166,
"vitaminB9": 36,
"vitaminB12": 1.22,
"vitaminC": 0,
"vitaminD": 0.5,
"vitaminE": 0.25,
"vitaminK": 2.4,
"magnesium": 23,
"calcium": 528,
"phosphorus": 387,
"potassium": 256,
"iron": 0.31,
"selenium": 14.5,
"zinc": 2.66,
"manganese": 0.009,
"copper": 0.04,
"choline": 15.4,
"volume": {
"portionId": "cups",
"weightInGrams": 135
}
},
{
"id": 525,
"name": "Egg Yolk",
"categoryId": 500,
"energy": 322,
"fat": 26.54,
"saturatedFat": 9.551,
"monounsaturatedFat": 11.738,
"polyunsaturatedFat": 4.204,
"carbs": 3.59,
"sugar": 0.56,
"fiber": 0,
"protein": 15.86,
"sodium": 48,
"cholesterol": 1085,
"vitaminA": 381,
"vitaminB1": 0.176,
"vitaminB2": 0.528,
"vitaminB3": 0.024,
"vitaminB5": 2.99,
"vitaminB6": 0.35,
"vitaminB9": 146,
"vitaminB12": 1.95,
"vitaminC": 0,
"vitaminD": 5.4,
"vitaminE": 2.58,
"vitaminK": 0.7,
"magnesium": 5,
"calcium": 129,
"phosphorus": 390,
"potassium": 109,
"iron": 2.73,
"selenium": 56,
"zinc": 2.3,
"manganese": 0.055,
"copper": 0.077,
"choline": 820.2,
"volume": {
"portionId": "cups",
"weightInGrams": 243
}
},
{
"id": 526,
"name": "Provolone Cheese",
"categoryId": 500,
"energy": 351,
"fat": 26.62,
"saturatedFat": 17.078,
"monounsaturatedFat": 7.393,
"polyunsaturatedFat": 0.769,
"carbs": 2.14,
"sugar": 0.56,
"fiber": 0,
"protein": 25.58,
"sodium": 727,
"cholesterol": 69,
"vitaminA": 236,
"vitaminB1": 0.019,
"vitaminB2": 0.321,
"vitaminB3": 0.156,
"vitaminB5": 0.476,
"vitaminB6": 0.073,
"vitaminB9": 10,
"vitaminB12": 1.46,
"vitaminC": 0,
"vitaminD": 0.5,
"vitaminE": 0.23,
"vitaminK": 2.2,
"magnesium": 28,
"calcium": 756,
"phosphorus": 496,
"potassium": 138,
"iron": 0.52,
"selenium": 14.5,
"zinc": 3.23,
"manganese": 0.01,
"copper": 0.026,
"choline": 15.4,
"volume": {
"portionId": "cups",
"weightInGrams": 132
}
},
{
"id": 527,
"name": "Reduced Fat Provolone Chesse",
"categoryId": 500,
"energy": 274,
"fat": 17.6,
"saturatedFat": 11.3,
"monounsaturatedFat": 4.89,
"polyunsaturatedFat": 0.51,
"carbs": 3.5,
"sugar": 0.55,
"fiber": 0,
"protein": 24.7,
"sodium": 615,
"cholesterol": 55,
"vitaminA": 141,
"vitaminB1": 0.019,
"vitaminB2": 0.321,
"vitaminB3": 0.156,
"vitaminB5": 0.476,
"vitaminB6": 0.073,
"vitaminB9": 10,
"vitaminB12": 1.46,
"vitaminC": 0,
"vitaminD": 0.3,
"vitaminE": 0.15,
"vitaminK": 1.5,
"magnesium": 28,
"calcium": 756,
"phosphorus": 496,
"potassium": 138,
"iron": 0.52,
"selenium": 14.5,
"zinc": 3.23,
"manganese": 0.01,
"copper": 0.026,
"choline": 12.9,
"volume": {
"portionId": "cups",
"weightInGrams": 113
}
},
{
"id": 528,
"name": "Swiss Cheese",
"categoryId": 500,
"energy": 393,
"fat": 30.99,
"saturatedFat": 18.227,
"monounsaturatedFat": 8.046,
"polyunsaturatedFat": 1.341,
"carbs": 1.44,
"sugar": 0,
"fiber": 0,
"protein": 26.96,
"sodium": 187,
"cholesterol": 93,
"vitaminA": 288,
"vitaminB1": 0.011,
"vitaminB2": 0.302,
"vitaminB3": 0.064,
"vitaminB5": 0.353,
"vitaminB6": 0.071,
"vitaminB9": 10,
"vitaminB12": 3.06,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.6,
"vitaminK": 1.4,
"magnesium": 33,
"calcium": 890,
"phosphorus": 574,
"potassium": 72,
"iron": 0.13,
"selenium": 30,
"zinc": 4.37,
"manganese": 0.026,
"copper": 0.047,
"choline": 13.8,
"volume": {
"portionId": "cups",
"weightInGrams": 244
}
},
{
"id": 529,
"name": "Low Fat Swiss Cheese",
"categoryId": 500,
"energy": 179,
"fat": 5.1,
"saturatedFat": 3.304,
"monounsaturatedFat": 1.351,
"polyunsaturatedFat": 0.18,
"carbs": 3.4,
"sugar": 1.33,
"fiber": 0,
"protein": 28.4,
"sodium": 199,
"cholesterol": 35,
"vitaminA": 40,
"vitaminB1": 0.02,
"vitaminB2": 0.36,
"vitaminB3": 0.09,
"vitaminB5": 0,
"vitaminB6": 0.08,
"vitaminB9": 6,
"vitaminB12": 1.68,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.07,
"vitaminK": 0.5,
"magnesium": 36,
"calcium": 961,
"phosphorus": 605,
"potassium": 111,
"iron": 0.17,
"selenium": 12.7,
"zinc": 3.9,
"manganese": 0,
"copper": 0.027,
"choline": 15.4,
"volume": {
"portionId": "cups",
"weightInGrams": 132
}
},
{
"id": 530,
"name": "White Queso Cheese",
"categoryId": 500,
"energy": 310,
"fat": 24.31,
"saturatedFat": 13.661,
"monounsaturatedFat": 6.459,
"polyunsaturatedFat": 1.149,
"carbs": 2.53,
"sugar": 1.76,
"fiber": 0,
"protein": 20.38,
"sodium": 704,
"cholesterol": 70,
"vitaminA": 157,
"vitaminB1": 0.048,
"vitaminB2": 0.23,
"vitaminB3": 0.035,
"vitaminB5": 0.397,
"vitaminB6": 0.086,
"vitaminB9": 0,
"vitaminB12": 1.75,
"vitaminC": 0,
"vitaminD": 0.7,
"vitaminE": 0.47,
"vitaminK": 1.6,
"magnesium": 29,
"calcium": 690,
"phosphorus": 467,
"potassium": 126,
"iron": 0.18,
"selenium": 13.8,
"zinc": 3.06,
"manganese": 0.021,
"copper": 0.025,
"choline": 15.4,
"volume": {
"portionId": "cups",
"weightInGrams": 118
}
},
{
"id": 531,
"name": "Part Skim Ricotta Cheese",
"categoryId": 500,
"energy": 138,
"fat": 7.91,
"saturatedFat": 4.927,
"monounsaturatedFat": 2.314,
"polyunsaturatedFat": 0.26,
"carbs": 5.14,
"sugar": 0.31,
"fiber": 0,
"protein": 11.39,
"sodium": 99,
"cholesterol": 31,
"vitaminA": 107,
"vitaminB1": 0.021,
"vitaminB2": 0.185,
"vitaminB3": 0.078,
"vitaminB5": 0.242,
"vitaminB6": 0.02,
"vitaminB9": 13,
"vitaminB12": 0.29,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.07,
"vitaminK": 0.7,
"magnesium": 15,
"calcium": 272,
"phosphorus": 183,
"potassium": 125,
"iron": 0.44,
"selenium": 16.7,
"zinc": 1.34,
"manganese": 0.01,
"copper": 0.034,
"choline": 16.3,
"volume": {
"portionId": "cups",
"weightInGrams": 124
}
},
{
"id": 532,
"name": "Egg White Wraps",
"categoryId": 500,
"energy": 89,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 17.86,
"sodium": 429,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 36,
"phosphorus": 0,
"potassium": 250,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
}
]
================================================
FILE: src/foods/builtIn/fatsAndOils.json
================================================
[
{
"id": 2001,
"name": "PAM cooking spray",
"categoryId": 2000,
"energy": 792,
"fat": 78.69,
"saturatedFat": 5.025,
"monounsaturatedFat": 49.792,
"polyunsaturatedFat": 22.145,
"carbs": 20.69,
"sugar": 0,
"fiber": 0,
"protein": 0.26,
"sodium": 59,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
},
{
"id": 2002,
"name": "Butter",
"categoryId": 2000,
"energy": 717,
"fat": 81.11,
"saturatedFat": 51.368,
"monounsaturatedFat": 21.021,
"polyunsaturatedFat": 3.043,
"carbs": 0.06,
"sugar": 0.06,
"fiber": 0,
"protein": 0.85,
"sodium": 643,
"cholesterol": 215,
"vitaminA": 684,
"vitaminB1": 0.005,
"vitaminB2": 0.034,
"vitaminB3": 0.042,
"vitaminB5": 0.11,
"vitaminB6": 0.003,
"vitaminB9": 3,
"vitaminB12": 0.17,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 2.32,
"vitaminK": 7,
"magnesium": 2,
"calcium": 24,
"phosphorus": 24,
"potassium": 24,
"iron": 0.02,
"selenium": 1,
"zinc": 0.09,
"manganese": 0,
"copper": 0,
"choline": 18.8,
"volume": {
"portionId": "cups",
"weightInGrams": 227
}
},
{
"id": 2003,
"name": "Olive Oil",
"categoryId": 2000,
"energy": 884,
"fat": 100,
"saturatedFat": 13.808,
"monounsaturatedFat": 72.961,
"polyunsaturatedFat": 10.523,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 14.35,
"vitaminK": 60.2,
"magnesium": 0,
"calcium": 1,
"phosphorus": 0,
"potassium": 1,
"iron": 0.56,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0.3,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 13.5
}
},
{
"id": 2004,
"name": "Coconut oil",
"categoryId": 2000,
"energy": 892,
"fat": 99.06,
"saturatedFat": 82.475,
"monounsaturatedFat": 6.332,
"polyunsaturatedFat": 1.702,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.11,
"vitaminK": 0.6,
"magnesium": 0,
"calcium": 1,
"phosphorus": 0,
"potassium": 0,
"iron": 0.05,
"selenium": 0,
"zinc": 0.02,
"manganese": 0,
"copper": 0,
"choline": 0.3,
"volume": {
"portionId": "cups",
"weightInGrams": 218
}
},
{
"id": 2005,
"name": "Avocado Oil",
"categoryId": 2000,
"energy": 884,
"fat": 100,
"saturatedFat": 11.56,
"monounsaturatedFat": 70.554,
"polyunsaturatedFat": 13.486,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 4.5
}
},
{
"id": 2006,
"name": "Flaxseed Oil",
"categoryId": 2000,
"energy": 884,
"fat": 99.98,
"saturatedFat": 8.976,
"monounsaturatedFat": 18.438,
"polyunsaturatedFat": 67.849,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0.11,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.47,
"vitaminK": 9.3,
"magnesium": 0,
"calcium": 1,
"phosphorus": 1,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0.07,
"manganese": 0,
"copper": 0,
"choline": 0.2,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 13.6
}
},
{
"id": 2007,
"name": "Canola Oil",
"categoryId": 2000,
"energy": 884,
"fat": 100,
"saturatedFat": 7.365,
"monounsaturatedFat": 63.276,
"polyunsaturatedFat": 28.142,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 17.46,
"vitaminK": 71.3,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0.2,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 4.5
}
},
{
"id": 2008,
"name": "Salmon Oil",
"categoryId": 2000,
"energy": 902,
"fat": 100,
"saturatedFat": 19.872,
"monounsaturatedFat": 29.037,
"polyunsaturatedFat": 40.324,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0,
"sodium": 0,
"cholesterol": 485,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 4.5
}
},
{
"id": 2009,
"name": "Italian Salad Dressing",
"categoryId": 2000,
"energy": 240,
"fat": 21.12,
"saturatedFat": 2.948,
"monounsaturatedFat": 5.638,
"polyunsaturatedFat": 10.748,
"carbs": 12.12,
"sugar": 10.77,
"fiber": 0,
"protein": 0.41,
"sodium": 993,
"cholesterol": 0,
"vitaminA": 2,
"vitaminB1": 0.02,
"vitaminB2": 0,
"vitaminB3": 0.131,
"vitaminB5": 0,
"vitaminB6": 0.064,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0.4,
"vitaminD": 0,
"vitaminE": 2.19,
"vitaminK": 56,
"magnesium": 5,
"calcium": 13,
"phosphorus": 15,
"potassium": 84,
"iron": 0.26,
"selenium": 2,
"zinc": 0.07,
"manganese": 0.031,
"copper": 0.019,
"choline": 2.6,
"volume": {
"portionId": "cups",
"weightInGrams": 235
}
},
{
"id": 2010,
"name": "Fat Free Italian Salad Dressing",
"categoryId": 2000,
"energy": 47,
"fat": 0.87,
"saturatedFat": 0.295,
"monounsaturatedFat": 0.235,
"polyunsaturatedFat": 0.192,
"carbs": 8.75,
"sugar": 8.85,
"fiber": 0.6,
"protein": 0.97,
"sodium": 1129,
"cholesterol": 2,
"vitaminA": 4,
"vitaminB1": 0.031,
"vitaminB2": 0.053,
"vitaminB3": 0.135,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 12,
"vitaminB12": 0.31,
"vitaminC": 0.4,
"vitaminD": 0,
"vitaminE": 0.76,
"vitaminK": 1.6,
"magnesium": 5,
"calcium": 30,
"phosphorus": 109,
"potassium": 102,
"iron": 0.4,
"selenium": 2,
"zinc": 0.36,
"manganese": 0.032,
"copper": 0.116,
"choline": 4,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 14
}
},
{
"id": 2011,
"name": "Light Italian Salad Dressing",
"categoryId": 2000,
"energy": 102,
"fat": 6.68,
"saturatedFat": 0.833,
"monounsaturatedFat": 1.725,
"polyunsaturatedFat": 3.236,
"carbs": 9.99,
"sugar": 9.16,
"fiber": 0,
"protein": 0.39,
"sodium": 891,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.012,
"vitaminB2": 0.008,
"vitaminB3": 0.094,
"vitaminB5": 0,
"vitaminB6": 0.055,
"vitaminB9": 3,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 4.28,
"vitaminK": 12.5,
"magnesium": 4,
"calcium": 15,
"phosphorus": 12,
"potassium": 90,
"iron": 0.25,
"selenium": 1.6,
"zinc": 0.06,
"manganese": 0,
"copper": 0.019,
"choline": 3.3
},
{
"id": 2012,
"name": "Light Mayonnaise",
"categoryId": 2000,
"energy": 238,
"fat": 22.22,
"saturatedFat": 3.446,
"monounsaturatedFat": 5.01,
"polyunsaturatedFat": 12.993,
"carbs": 9.23,
"sugar": 3.56,
"fiber": 0,
"protein": 0.37,
"sodium": 827,
"cholesterol": 16,
"vitaminA": 8,
"vitaminB1": 0.008,
"vitaminB2": 0,
"vitaminB3": 0.01,
"vitaminB5": 0.058,
"vitaminB6": 0.002,
"vitaminB9": 4,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 2.19,
"vitaminK": 53.7,
"magnesium": 2,
"calcium": 6,
"phosphorus": 15,
"potassium": 31,
"iron": 0.14,
"selenium": 2.6,
"zinc": 0.07,
"manganese": 0.007,
"copper": 0.019,
"choline": 9,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 15
}
},
{
"id": 2013,
"name": "Mayonnaise",
"categoryId": 2000,
"energy": 680,
"fat": 74.85,
"saturatedFat": 11.703,
"monounsaturatedFat": 16.843,
"polyunsaturatedFat": 44.69,
"carbs": 0.57,
"sugar": 0.57,
"fiber": 0,
"protein": 0.96,
"sodium": 635,
"cholesterol": 42,
"vitaminA": 16,
"vitaminB1": 0.01,
"vitaminB2": 0.019,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0.008,
"vitaminB9": 5,
"vitaminB12": 0.12,
"vitaminC": 0,
"vitaminD": 0.2,
"vitaminE": 3.28,
"vitaminK": 163,
"magnesium": 1,
"calcium": 8,
"phosphorus": 21,
"potassium": 20,
"iron": 0.21,
"selenium": 2.3,
"zinc": 0.15,
"manganese": 0,
"copper": 0.019,
"choline": 34.2
}
]
================================================
FILE: src/foods/builtIn/finfishAndShellFish.json
================================================
[
{
"id": 401,
"name": "Wild Atlantic Salmon",
"categoryId": 400,
"energy": 142,
"fat": 6.34,
"saturatedFat": 0.981,
"monounsaturatedFat": 2.103,
"polyunsaturatedFat": 2.539,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 19.84,
"sodium": 44,
"cholesterol": 55,
"vitaminA": 12,
"vitaminB1": 0.226,
"vitaminB2": 0.38,
"vitaminB3": 7.86,
"vitaminB5": 1.664,
"vitaminB6": 0.818,
"vitaminB9": 25,
"vitaminB12": 3.18,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 29,
"calcium": 12,
"phosphorus": 200,
"potassium": 490,
"iron": 0.8,
"selenium": 36.5,
"zinc": 0.64,
"manganese": 0.016,
"copper": 0.25,
"choline": 0
},
{
"id": 402,
"name": "Canned Tuna (in water)",
"categoryId": 400,
"energy": 128,
"fat": 2.97,
"saturatedFat": 0.792,
"monounsaturatedFat": 0.784,
"polyunsaturatedFat": 1.109,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 23.62,
"sodium": 377,
"cholesterol": 42,
"vitaminA": 6,
"vitaminB1": 0.008,
"vitaminB2": 0.044,
"vitaminB3": 5.799,
"vitaminB5": 0.124,
"vitaminB6": 0.217,
"vitaminB9": 2,
"vitaminB12": 1.17,
"vitaminC": 0,
"vitaminD": 2,
"vitaminE": 0.85,
"vitaminK": 2.5,
"magnesium": 33,
"calcium": 14,
"phosphorus": 217,
"potassium": 237,
"iron": 0.97,
"selenium": 65.7,
"zinc": 0.48,
"manganese": 0.019,
"copper": 0.039,
"choline": 29.3
},
{
"id": 403,
"name": "Shrimp",
"categoryId": 400,
"energy": 85,
"fat": 0.51,
"saturatedFat": 0.101,
"monounsaturatedFat": 0.086,
"polyunsaturatedFat": 0.152,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 20.1,
"sodium": 119,
"cholesterol": 161,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 35,
"calcium": 64,
"phosphorus": 214,
"potassium": 264,
"iron": 0.52,
"selenium": 0,
"zinc": 1.34,
"manganese": 0.033,
"copper": 0.391,
"choline": 0
},
{
"id": 404,
"name": "Canned Salmon",
"categoryId": 400,
"energy": 137,
"fat": 5.48,
"saturatedFat": 1.009,
"monounsaturatedFat": 1.499,
"polyunsaturatedFat": 1.497,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 20.55,
"sodium": 403,
"cholesterol": 59,
"vitaminA": 25,
"vitaminB1": 0.025,
"vitaminB2": 0.19,
"vitaminB3": 6.776,
"vitaminB5": 0,
"vitaminB6": 0.268,
"vitaminB9": 13,
"vitaminB12": 4.62,
"vitaminC": 0,
"vitaminD": 15,
"vitaminE": 0.97,
"vitaminK": 0.4,
"magnesium": 30,
"calcium": 220,
"phosphorus": 338,
"potassium": 336,
"iron": 0.64,
"selenium": 33.9,
"zinc": 0.79,
"manganese": 0,
"copper": 0.071,
"choline": 86.6
},
{
"id": 405,
"name": "Atlantic Cod",
"categoryId": 400,
"energy": 82,
"fat": 0.67,
"saturatedFat": 0.131,
"monounsaturatedFat": 0.094,
"polyunsaturatedFat": 0.231,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 17.81,
"sodium": 54,
"cholesterol": 43,
"vitaminA": 12,
"vitaminB1": 0.076,
"vitaminB2": 0.065,
"vitaminB3": 2.063,
"vitaminB5": 0.153,
"vitaminB6": 0.245,
"vitaminB9": 7,
"vitaminB12": 0.91,
"vitaminC": 1,
"vitaminD": 0.9,
"vitaminE": 0.64,
"vitaminK": 0.1,
"magnesium": 32,
"calcium": 16,
"phosphorus": 203,
"potassium": 413,
"iron": 0.38,
"selenium": 33.1,
"zinc": 0.45,
"manganese": 0.015,
"copper": 0.028,
"choline": 65.2
},
{
"id": 406,
"name": "Tilapia",
"categoryId": 400,
"energy": 96,
"fat": 1.7,
"saturatedFat": 0.585,
"monounsaturatedFat": 0.498,
"polyunsaturatedFat": 0.363,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 20.08,
"sodium": 52,
"cholesterol": 50,
"vitaminA": 0,
"vitaminB1": 0.041,
"vitaminB2": 0.063,
"vitaminB3": 3.903,
"vitaminB5": 0.487,
"vitaminB6": 0.162,
"vitaminB9": 24,
"vitaminB12": 1.58,
"vitaminC": 0,
"vitaminD": 3.1,
"vitaminE": 0.4,
"vitaminK": 1.4,
"magnesium": 27,
"calcium": 10,
"phosphorus": 170,
"potassium": 302,
"iron": 0.56,
"selenium": 41.8,
"zinc": 0.33,
"manganese": 0.037,
"copper": 0.075,
"choline": 42.5
},
{
"id": 407,
"name": "Smoked Salmon",
"categoryId": 400,
"energy": 117,
"fat": 4.32,
"saturatedFat": 0.929,
"monounsaturatedFat": 2.023,
"polyunsaturatedFat": 0.995,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 18.28,
"sodium": 672,
"cholesterol": 23,
"vitaminA": 26,
"vitaminB1": 0.023,
"vitaminB2": 0.101,
"vitaminB3": 4.72,
"vitaminB5": 0,
"vitaminB6": 0.278,
"vitaminB9": 2,
"vitaminB12": 3.26,
"vitaminC": 0,
"vitaminD": 17.1,
"vitaminE": 1.35,
"vitaminK": 0.1,
"magnesium": 18,
"calcium": 11,
"phosphorus": 164,
"potassium": 175,
"iron": 0.85,
"selenium": 32.4,
"zinc": 0.31,
"manganese": 0,
"copper": 0.23,
"choline": 89
},
{
"id": 408,
"name": "Cod",
"categoryId": 400,
"energy": 82,
"fat": 0.67,
"saturatedFat": 0.131,
"monounsaturatedFat": 0.094,
"polyunsaturatedFat": 0.231,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 17.81,
"sodium": 54,
"cholesterol": 43,
"vitaminA": 12,
"vitaminB1": 0.076,
"vitaminB2": 0.065,
"vitaminB3": 2.063,
"vitaminB5": 0.153,
"vitaminB6": 0.245,
"vitaminB9": 7,
"vitaminB12": 0.91,
"vitaminC": 1,
"vitaminD": 0.9,
"vitaminE": 0.64,
"vitaminK": 0.1,
"magnesium": 32,
"calcium": 16,
"phosphorus": 203,
"potassium": 413,
"iron": 0.38,
"selenium": 33.1,
"zinc": 0.45,
"manganese": 0.015,
"copper": 0.028,
"choline": 65.2
},
{
"id": 409,
"name": "Halibut",
"categoryId": 400,
"energy": 91,
"fat": 1.33,
"saturatedFat": 0.292,
"monounsaturatedFat": 0.471,
"polyunsaturatedFat": 0.29,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 18.56,
"sodium": 68,
"cholesterol": 49,
"vitaminA": 20,
"vitaminB1": 0.05,
"vitaminB2": 0.03,
"vitaminB3": 6.513,
"vitaminB5": 0.343,
"vitaminB6": 0.548,
"vitaminB9": 12,
"vitaminB12": 1.1,
"vitaminC": 0,
"vitaminD": 4.7,
"vitaminE": 0.61,
"vitaminK": 0,
"magnesium": 23,
"calcium": 7,
"phosphorus": 236,
"potassium": 435,
"iron": 0.16,
"selenium": 45.6,
"zinc": 0.36,
"manganese": 0.011,
"copper": 0.023,
"choline": 61.8
},
{
"id": 410,
"name": "Haddock",
"categoryId": 400,
"energy": 74,
"fat": 0.45,
"saturatedFat": 0.091,
"monounsaturatedFat": 0.061,
"polyunsaturatedFat": 0.166,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 16.32,
"sodium": 213,
"cholesterol": 54,
"vitaminA": 17,
"vitaminB1": 0.02,
"vitaminB2": 0.057,
"vitaminB3": 3.363,
"vitaminB5": 0.403,
"vitaminB6": 0.281,
"vitaminB9": 12,
"vitaminB12": 1.83,
"vitaminC": 0,
"vitaminD": 0.5,
"vitaminE": 0.45,
"vitaminK": 0.1,
"magnesium": 21,
"calcium": 11,
"phosphorus": 227,
"potassium": 286,
"iron": 0.17,
"selenium": 25.9,
"zinc": 0.32,
"manganese": 0.011,
"copper": 0.021,
"choline": 65
},
{
"id": 411,
"name": "Trout",
"categoryId": 400,
"energy": 148,
"fat": 6.61,
"saturatedFat": 1.149,
"monounsaturatedFat": 3.254,
"polyunsaturatedFat": 1.499,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 20.77,
"sodium": 52,
"cholesterol": 58,
"vitaminA": 17,
"vitaminB1": 0.35,
"vitaminB2": 0.33,
"vitaminB3": 4.5,
"vitaminB5": 1.94,
"vitaminB6": 0.2,
"vitaminB9": 13,
"vitaminB12": 7.79,
"vitaminC": 0.5,
"vitaminD": 3.9,
"vitaminE": 0.2,
"vitaminK": 0.1,
"magnesium": 22,
"calcium": 43,
"phosphorus": 245,
"potassium": 361,
"iron": 1.5,
"selenium": 12.6,
"zinc": 0.66,
"manganese": 0.851,
"copper": 0.188,
"choline": 65
},
{
"id": 412,
"name": "Lobster",
"categoryId": 400,
"energy": 77,
"fat": 0.75,
"saturatedFat": 0.181,
"monounsaturatedFat": 0.22,
"polyunsaturatedFat": 0.296,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 16.52,
"sodium": 423,
"cholesterol": 127,
"vitaminA": 1,
"vitaminB1": 0.02,
"vitaminB2": 0.014,
"vitaminB3": 1.591,
"vitaminB5": 1.449,
"vitaminB6": 0.104,
"vitaminB9": 10,
"vitaminB12": 1.25,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.87,
"vitaminK": 0,
"magnesium": 38,
"calcium": 84,
"phosphorus": 161,
"potassium": 200,
"iron": 0.26,
"selenium": 63.6,
"zinc": 3.53,
"manganese": 0.056,
"copper": 1.349,
"choline": 70.3
},
{
"id": 413,
"name": "Pacific Oyster",
"categoryId": 400,
"energy": 81,
"fat": 2.3,
"saturatedFat": 0.51,
"monounsaturatedFat": 0.358,
"polyunsaturatedFat": 0.894,
"carbs": 4.95,
"sugar": 0,
"fiber": 0,
"protein": 9.45,
"sodium": 106,
"cholesterol": 50,
"vitaminA": 81,
"vitaminB1": 0.067,
"vitaminB2": 0.233,
"vitaminB3": 2.01,
"vitaminB5": 0.5,
"vitaminB6": 0.05,
"vitaminB9": 10,
"vitaminB12": 16,
"vitaminC": 8,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 22,
"calcium": 8,
"phosphorus": 162,
"potassium": 168,
"iron": 5.11,
"selenium": 77,
"zinc": 16.62,
"manganese": 0.643,
"copper": 1.576,
"choline": 0
},
{
"id": 414,
"name": "Squid",
"categoryId": 400,
"energy": 92,
"fat": 1.38,
"saturatedFat": 0.358,
"monounsaturatedFat": 0.107,
"polyunsaturatedFat": 0.524,
"carbs": 3.08,
"sugar": 0,
"fiber": 0,
"protein": 15.58,
"sodium": 44,
"cholesterol": 233,
"vitaminA": 10,
"vitaminB1": 0.02,
"vitaminB2": 0.412,
"vitaminB3": 2.175,
"vitaminB5": 0.5,
"vitaminB6": 0.056,
"vitaminB9": 5,
"vitaminB12": 1.3,
"vitaminC": 4.7,
"vitaminD": 0,
"vitaminE": 1.2,
"vitaminK": 0,
"magnesium": 33,
"calcium": 32,
"phosphorus": 221,
"potassium": 246,
"iron": 0.68,
"selenium": 44.8,
"zinc": 1.53,
"manganese": 0.035,
"copper": 1.891,
"choline": 65
}
]
================================================
FILE: src/foods/builtIn/fruitsAndJuices.json
================================================
[
{
"id": 901,
"name": "Tomatoes",
"categoryId": 900,
"energy": 18,
"fat": 0.2,
"saturatedFat": 0.028,
"monounsaturatedFat": 0.031,
"polyunsaturatedFat": 0.083,
"carbs": 3.89,
"sugar": 2.63,
"fiber": 1.2,
"protein": 0.88,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 42,
"vitaminB1": 0.037,
"vitaminB2": 0.019,
"vitaminB3": 0.594,
"vitaminB5": 0,
"vitaminB6": 0.08,
"vitaminB9": 15,
"vitaminB12": 0,
"vitaminC": 13.7,
"vitaminD": 0,
"vitaminE": 0.54,
"vitaminK": 7.9,
"magnesium": 11,
"calcium": 10,
"phosphorus": 24,
"potassium": 237,
"iron": 0.27,
"selenium": 0,
"zinc": 0.17,
"manganese": 0,
"copper": 0.059,
"choline": 6.7
},
{
"id": 902,
"name": "Lemon Juice",
"categoryId": 900,
"energy": 22,
"fat": 0.24,
"saturatedFat": 0.04,
"monounsaturatedFat": 0.006,
"polyunsaturatedFat": 0.021,
"carbs": 6.9,
"sugar": 2.52,
"fiber": 0.3,
"protein": 0.35,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.024,
"vitaminB2": 0.015,
"vitaminB3": 0.091,
"vitaminB5": 0.131,
"vitaminB6": 0.046,
"vitaminB9": 20,
"vitaminB12": 0,
"vitaminC": 38.7,
"vitaminD": 0,
"vitaminE": 0.15,
"vitaminK": 0,
"magnesium": 6,
"calcium": 6,
"phosphorus": 8,
"potassium": 103,
"iron": 0.08,
"selenium": 0.1,
"zinc": 0.05,
"manganese": 0.012,
"copper": 0.016,
"choline": 5.1,
"volume": {
"portionId": "cups",
"weightInGrams": 244
}
},
{
"id": 903,
"name": "Raisins",
"categoryId": 900,
"energy": 299,
"fat": 0.25,
"saturatedFat": 0.094,
"monounsaturatedFat": 0.024,
"polyunsaturatedFat": 0.053,
"carbs": 79.32,
"sugar": 65.18,
"fiber": 4.5,
"protein": 3.3,
"sodium": 26,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.106,
"vitaminB2": 0.125,
"vitaminB3": 0.766,
"vitaminB5": 0,
"vitaminB6": 0.174,
"vitaminB9": 5,
"vitaminB12": 0,
"vitaminC": 2.3,
"vitaminD": 0,
"vitaminE": 0.12,
"vitaminK": 3.5,
"magnesium": 36,
"calcium": 62,
"phosphorus": 98,
"potassium": 744,
"iron": 1.79,
"selenium": 0.6,
"zinc": 0.36,
"manganese": 0,
"copper": 0.272,
"choline": 11.1
},
{
"id": 904,
"name": "Orange Juice",
"categoryId": 900,
"energy": 47,
"fat": 0.15,
"saturatedFat": 0.018,
"monounsaturatedFat": 0.025,
"polyunsaturatedFat": 0.034,
"carbs": 11.01,
"sugar": 8.76,
"fiber": 0.3,
"protein": 0.68,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 9,
"vitaminB1": 0.039,
"vitaminB2": 0.021,
"vitaminB3": 0.201,
"vitaminB5": 0.18,
"vitaminB6": 0.031,
"vitaminB9": 24,
"vitaminB12": 0,
"vitaminC": 30.1,
"vitaminD": 0,
"vitaminE": 0.2,
"vitaminK": 0.1,
"magnesium": 10,
"calcium": 10,
"phosphorus": 17,
"potassium": 184,
"iron": 0.1,
"selenium": 0.1,
"zinc": 0.04,
"manganese": 0.021,
"copper": 0.022,
"choline": 6.2,
"volume": {
"portionId": "cups",
"weightInGrams": 249
}
},
{
"id": 905,
"name": "Raspberries",
"categoryId": 900,
"energy": 52,
"fat": 0.65,
"saturatedFat": 0.019,
"monounsaturatedFat": 0.064,
"polyunsaturatedFat": 0.375,
"carbs": 11.94,
"sugar": 4.42,
"fiber": 6.5,
"protein": 1.2,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 2,
"vitaminB1": 0.032,
"vitaminB2": 0.038,
"vitaminB3": 0.598,
"vitaminB5": 0.329,
"vitaminB6": 0.055,
"vitaminB9": 21,
"vitaminB12": 0,
"vitaminC": 26.2,
"vitaminD": 0,
"vitaminE": 0.87,
"vitaminK": 7.8,
"magnesium": 22,
"calcium": 25,
"phosphorus": 29,
"potassium": 151,
"iron": 0.69,
"selenium": 0.2,
"zinc": 0.42,
"manganese": 0.67,
"copper": 0.09,
"choline": 12.3,
"volume": {
"portionId": "cups",
"weightInGrams": 123
}
},
{
"id": 906,
"name": "Strawberries",
"categoryId": 900,
"energy": 32,
"fat": 0.3,
"saturatedFat": 0.015,
"monounsaturatedFat": 0.043,
"polyunsaturatedFat": 0.155,
"carbs": 7.68,
"sugar": 4.89,
"fiber": 2,
"protein": 0.67,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.024,
"vitaminB2": 0.022,
"vitaminB3": 0.386,
"vitaminB5": 0.125,
"vitaminB6": 0.047,
"vitaminB9": 24,
"vitaminB12": 0,
"vitaminC": 58.8,
"vitaminD": 0,
"vitaminE": 0.29,
"vitaminK": 2.2,
"magnesium": 13,
"calcium": 16,
"phosphorus": 24,
"potassium": 153,
"iron": 0.41,
"selenium": 0.4,
"zinc": 0.14,
"manganese": 0.386,
"copper": 0.048,
"choline": 5.7,
"volume": {
"portionId": "cups",
"weightInGrams": 232
}
},
{
"id": 907,
"name": "Blackberries",
"categoryId": 900,
"energy": 43,
"fat": 0.49,
"saturatedFat": 0.014,
"monounsaturatedFat": 0.047,
"polyunsaturatedFat": 0.28,
"carbs": 9.61,
"sugar": 4.88,
"fiber": 5.3,
"protein": 1.39,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 11,
"vitaminB1": 0.02,
"vitaminB2": 0.026,
"vitaminB3": 0.646,
"vitaminB5": 0.276,
"vitaminB6": 0.03,
"vitaminB9": 25,
"vitaminB12": 0,
"vitaminC": 21,
"vitaminD": 0,
"vitaminE": 1.17,
"vitaminK": 19.8,
"magnesium": 20,
"calcium": 29,
"phosphorus": 22,
"potassium": 162,
"iron": 0.62,
"selenium": 0.4,
"zinc": 0.53,
"manganese": 0.646,
"copper": 0.165,
"choline": 8.5,
"volume": {
"portionId": "cups",
"weightInGrams": 144
}
},
{
"id": 908,
"name": "Bananas",
"categoryId": 900,
"energy": 89,
"fat": 0.33,
"saturatedFat": 0.112,
"monounsaturatedFat": 0.032,
"polyunsaturatedFat": 0.073,
"carbs": 22.84,
"sugar": 12.23,
"fiber": 2.6,
"protein": 1.09,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 0.031,
"vitaminB2": 0.073,
"vitaminB3": 0.665,
"vitaminB5": 0.334,
"vitaminB6": 0.367,
"vitaminB9": 20,
"vitaminB12": 0,
"vitaminC": 8.7,
"vitaminD": 0,
"vitaminE": 0.1,
"vitaminK": 0.5,
"magnesium": 27,
"calcium": 5,
"phosphorus": 22,
"potassium": 358,
"iron": 0.26,
"selenium": 1,
"zinc": 0.15,
"manganese": 0.27,
"copper": 0.078,
"choline": 9.8,
"volume": {
"portionId": "cups",
"weightInGrams": 150
}
},
{
"id": 909,
"name": "Blueberries",
"categoryId": 900,
"energy": 57,
"fat": 0.33,
"saturatedFat": 0.028,
"monounsaturatedFat": 0.047,
"polyunsaturatedFat": 0.146,
"carbs": 14.49,
"sugar": 9.96,
"fiber": 2.4,
"protein": 0.74,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 0.037,
"vitaminB2": 0.041,
"vitaminB3": 0.418,
"vitaminB5": 0.124,
"vitaminB6": 0.052,
"vitaminB9": 6,
"vitaminB12": 0,
"vitaminC": 9.7,
"vitaminD": 0,
"vitaminE": 0.57,
"vitaminK": 19.3,
"magnesium": 6,
"calcium": 6,
"phosphorus": 12,
"potassium": 77,
"iron": 0.28,
"selenium": 0.1,
"zinc": 0.16,
"manganese": 0.336,
"copper": 0.057,
"choline": 6,
"volume": {
"portionId": "cups",
"weightInGrams": 148
}
},
{
"id": 910,
"name": "Cherries",
"categoryId": 900,
"energy": 63,
"fat": 0.2,
"saturatedFat": 0.038,
"monounsaturatedFat": 0.047,
"polyunsaturatedFat": 0.052,
"carbs": 16.01,
"sugar": 12.82,
"fiber": 2.1,
"protein": 1.06,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 0.027,
"vitaminB2": 0.033,
"vitaminB3": 0.154,
"vitaminB5": 0.199,
"vitaminB6": 0.049,
"vitaminB9": 4,
"vitaminB12": 0,
"vitaminC": 7,
"vitaminD": 0,
"vitaminE": 0.07,
"vitaminK": 2.1,
"magnesium": 11,
"calcium": 13,
"phosphorus": 21,
"potassium": 222,
"iron": 0.36,
"selenium": 0,
"zinc": 0.07,
"manganese": 0.07,
"copper": 0.06,
"choline": 6.1,
"volume": {
"portionId": "cups",
"weightInGrams": 154
}
},
{
"id": 911,
"name": "Peaches",
"categoryId": 900,
"energy": 39,
"fat": 0.25,
"saturatedFat": 0.019,
"monounsaturatedFat": 0.067,
"polyunsaturatedFat": 0.086,
"carbs": 9.54,
"sugar": 8.39,
"fiber": 1.5,
"protein": 0.91,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 16,
"vitaminB1": 0.024,
"vitaminB2": 0.031,
"vitaminB3": 0.806,
"vitaminB5": 0.153,
"vitaminB6": 0.025,
"vitaminB9": 4,
"vitaminB12": 0,
"vitaminC": 6.6,
"vitaminD": 0,
"vitaminE": 0.73,
"vitaminK": 2.6,
"magnesium": 9,
"calcium": 6,
"phosphorus": 20,
"potassium": 190,
"iron": 0.25,
"selenium": 0.1,
"zinc": 0.17,
"manganese": 0.061,
"copper": 0.068,
"choline": 6.1,
"volume": {
"portionId": "cups",
"weightInGrams": 154
}
},
{
"id": 912,
"name": "Crushed Tomatoes (canned)",
"categoryId": 900,
"energy": 32,
"fat": 0.28,
"saturatedFat": 0.04,
"monounsaturatedFat": 0.043,
"polyunsaturatedFat": 0.113,
"carbs": 7.29,
"sugar": 4.4,
"fiber": 1.9,
"protein": 1.64,
"sodium": 186,
"cholesterol": 0,
"vitaminA": 11,
"vitaminB1": 0.075,
"vitaminB2": 0.052,
"vitaminB3": 1.222,
"vitaminB5": 0.278,
"vitaminB6": 0.15,
"vitaminB9": 13,
"vitaminB12": 0,
"vitaminC": 9.2,
"vitaminD": 0,
"vitaminE": 1.25,
"vitaminK": 5.3,
"magnesium": 20,
"calcium": 34,
"phosphorus": 32,
"potassium": 293,
"iron": 1.3,
"selenium": 0.6,
"zinc": 0.27,
"manganese": 0.183,
"copper": 0.183,
"choline": 12.9,
"volume": {
"portionId": "cups",
"weightInGrams": 121
}
},
{
"id": 913,
"name": "Pears",
"categoryId": 900,
"energy": 57,
"fat": 0.14,
"saturatedFat": 0.022,
"monounsaturatedFat": 0.084,
"polyunsaturatedFat": 0.094,
"carbs": 15.23,
"sugar": 9.75,
"fiber": 3.1,
"protein": 0.36,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.012,
"vitaminB2": 0.026,
"vitaminB3": 0.161,
"vitaminB5": 0.049,
"vitaminB6": 0.029,
"vitaminB9": 7,
"vitaminB12": 0,
"vitaminC": 4.3,
"vitaminD": 0,
"vitaminE": 0.12,
"vitaminK": 4.4,
"magnesium": 7,
"calcium": 9,
"phosphorus": 12,
"potassium": 116,
"iron": 0.18,
"selenium": 0.1,
"zinc": 0.1,
"manganese": 0.048,
"copper": 0.082,
"choline": 5.1,
"volume": {
"portionId": "cups",
"weightInGrams": 161
}
},
{
"id": 914,
"name": "Apples",
"categoryId": 900,
"energy": 52,
"fat": 0.17,
"saturatedFat": 0.028,
"monounsaturatedFat": 0.007,
"polyunsaturatedFat": 0.051,
"carbs": 13.81,
"sugar": 10.39,
"fiber": 2.4,
"protein": 0.26,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 0.017,
"vitaminB2": 0.026,
"vitaminB3": 0.091,
"vitaminB5": 0,
"vitaminB6": 0.041,
"vitaminB9": 3,
"vitaminB12": 0,
"vitaminC": 4.6,
"vitaminD": 0,
"vitaminE": 0.18,
"vitaminK": 2.2,
"magnesium": 5,
"calcium": 6,
"phosphorus": 11,
"potassium": 107,
"iron": 0.12,
"selenium": 0,
"zinc": 0.04,
"manganese": 0,
"copper": 0.027,
"choline": 3.4
},
{
"id": 915,
"name": "Grapes",
"categoryId": 900,
"energy": 69,
"fat": 0.16,
"saturatedFat": 0.054,
"monounsaturatedFat": 0.007,
"polyunsaturatedFat": 0.048,
"carbs": 18.1,
"sugar": 15.48,
"fiber": 0.9,
"protein": 0.72,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 0.069,
"vitaminB2": 0.07,
"vitaminB3": 0.188,
"vitaminB5": 0,
"vitaminB6": 0.086,
"vitaminB9": 2,
"vitaminB12": 0,
"vitaminC": 3.2,
"vitaminD": 0,
"vitaminE": 0.19,
"vitaminK": 14.6,
"magnesium": 7,
"calcium": 10,
"phosphorus": 20,
"potassium": 191,
"iron": 0.36,
"selenium": 0.1,
"zinc": 0.07,
"manganese": 0,
"copper": 0.127,
"choline": 5.6
},
{
"id": 916,
"name": "Avocado",
"categoryId": 900,
"energy": 160,
"fat": 14.66,
"saturatedFat": 2.126,
"monounsaturatedFat": 9.799,
"polyunsaturatedFat": 1.816,
"carbs": 8.53,
"sugar": 0.66,
"fiber": 6.7,
"protein": 2,
"sodium": 7,
"cholesterol": 0,
"vitaminA": 7,
"vitaminB1": 0.067,
"vitaminB2": 0.13,
"vitaminB3": 1.738,
"vitaminB5": 1.389,
"vitaminB6": 0.257,
"vitaminB9": 81,
"vitaminB12": 0,
"vitaminC": 10,
"vitaminD": 0,
"vitaminE": 2.07,
"vitaminK": 21,
"magnesium": 29,
"calcium": 12,
"phosphorus": 52,
"potassium": 485,
"iron": 0.55,
"selenium": 0.4,
"zinc": 0.64,
"manganese": 0.142,
"copper": 0.19,
"choline": 14.2,
"volume": {
"portionId": "cups",
"weightInGrams": 230
}
},
{
"id": 917,
"name": "Plums",
"categoryId": 900,
"energy": 46,
"fat": 0.28,
"saturatedFat": 0.017,
"monounsaturatedFat": 0.134,
"polyunsaturatedFat": 0.044,
"carbs": 11.42,
"sugar": 9.92,
"fiber": 1.4,
"protein": 0.7,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 17,
"vitaminB1": 0.028,
"vitaminB2": 0.026,
"vitaminB3": 0.417,
"vitaminB5": 0.135,
"vitaminB6": 0.029,
"vitaminB9": 5,
"vitaminB12": 0,
"vitaminC": 9.5,
"vitaminD": 0,
"vitaminE": 0.26,
"vitaminK": 6.4,
"magnesium": 7,
"calcium": 6,
"phosphorus": 16,
"potassium": 157,
"iron": 0.17,
"selenium": 0,
"zinc": 0.1,
"manganese": 0.052,
"copper": 0.057,
"choline": 1.9,
"volume": {
"portionId": "cups",
"weightInGrams": 165
}
},
{
"id": 918,
"name": "Mangos",
"categoryId": 900,
"energy": 60,
"fat": 0.38,
"saturatedFat": 0.092,
"monounsaturatedFat": 0.14,
"polyunsaturatedFat": 0.071,
"carbs": 14.98,
"sugar": 13.66,
"fiber": 1.6,
"protein": 0.82,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 54,
"vitaminB1": 0.028,
"vitaminB2": 0.038,
"vitaminB3": 0.669,
"vitaminB5": 0.197,
"vitaminB6": 0.119,
"vitaminB9": 43,
"vitaminB12": 0,
"vitaminC": 36.4,
"vitaminD": 0,
"vitaminE": 0.9,
"vitaminK": 4.2,
"magnesium": 10,
"calcium": 11,
"phosphorus": 14,
"potassium": 168,
"iron": 0.16,
"selenium": 0.6,
"zinc": 0.09,
"manganese": 0.063,
"copper": 0.111,
"choline": 7.6,
"volume": {
"portionId": "cups",
"weightInGrams": 165
}
},
{
"id": 919,
"name": "Pineapple",
"categoryId": 900,
"energy": 50,
"fat": 0.12,
"saturatedFat": 0.009,
"monounsaturatedFat": 0.013,
"polyunsaturatedFat": 0.04,
"carbs": 13.12,
"sugar": 9.85,
"fiber": 1.4,
"protein": 0.54,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 0.079,
"vitaminB2": 0.032,
"vitaminB3": 0.5,
"vitaminB5": 0.213,
"vitaminB6": 0.112,
"vitaminB9": 18,
"vitaminB12": 0,
"vitaminC": 47.8,
"vitaminD": 0,
"vitaminE": 0.02,
"vitaminK": 0.7,
"magnesium": 12,
"calcium": 13,
"phosphorus": 8,
"potassium": 109,
"iron": 0.29,
"selenium": 0.1,
"zinc": 0.12,
"manganese": 0.927,
"copper": 0.11,
"choline": 5.5,
"volume": {
"portionId": "cups",
"weightInGrams": 165
}
},
{
"id": 920,
"name": "Kiwi",
"categoryId": 900,
"energy": 58,
"fat": 0.44,
"saturatedFat": 0.029,
"monounsaturatedFat": 0.047,
"polyunsaturatedFat": 0.287,
"carbs": 14,
"sugar": 8.99,
"fiber": 3,
"protein": 1.06,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 4,
"vitaminB1": 0.027,
"vitaminB2": 0.025,
"vitaminB3": 0.37,
"vitaminB5": 0,
"vitaminB6": 0.061,
"vitaminB9": 26,
"vitaminB12": 0,
"vitaminC": 74.7,
"vitaminD": 0,
"vitaminE": 1.3,
"vitaminK": 40.3,
"magnesium": 16,
"calcium": 35,
"phosphorus": 34,
"potassium": 198,
"iron": 0.24,
"selenium": 0.2,
"zinc": 0.14,
"manganese": 0,
"copper": 0.134,
"choline": 7.8
},
{
"id": 921,
"name": "Pickled Olives",
"categoryId": 900,
"energy": 145,
"fat": 15.32,
"saturatedFat": 2.029,
"monounsaturatedFat": 11.314,
"polyunsaturatedFat": 1.307,
"carbs": 3.84,
"sugar": 0.54,
"fiber": 3.3,
"protein": 1.03,
"sodium": 1556,
"cholesterol": 0,
"vitaminA": 20,
"vitaminB1": 0.021,
"vitaminB2": 0.007,
"vitaminB3": 0.237,
"vitaminB5": 0.023,
"vitaminB6": 0.031,
"vitaminB9": 3,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 3.81,
"vitaminK": 1.4,
"magnesium": 11,
"calcium": 52,
"phosphorus": 4,
"potassium": 42,
"iron": 0.49,
"selenium": 0.9,
"zinc": 0.04,
"manganese": 0,
"copper": 0.12,
"choline": 14.2
},
{
"id": 922,
"name": "Grapefruit",
"categoryId": 900,
"energy": 32,
"fat": 0.1,
"saturatedFat": 0.014,
"monounsaturatedFat": 0.013,
"polyunsaturatedFat": 0.024,
"carbs": 8.08,
"sugar": 6.98,
"fiber": 1.1,
"protein": 0.63,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 46,
"vitaminB1": 0.036,
"vitaminB2": 0.02,
"vitaminB3": 0.25,
"vitaminB5": 0.283,
"vitaminB6": 0.042,
"vitaminB9": 10,
"vitaminB12": 0,
"vitaminC": 34.4,
"vitaminD": 0,
"vitaminE": 0.13,
"vitaminK": 0,
"magnesium": 8,
"calcium": 12,
"phosphorus": 8,
"potassium": 139,
"iron": 0.09,
"selenium": 0.3,
"zinc": 0.07,
"manganese": 0.012,
"copper": 0.047,
"choline": 7.7,
"volume": {
"portionId": "cups",
"weightInGrams": 230
}
},
{
"id": 923,
"name": "Sugar-apples",
"categoryId": 900,
"energy": 94,
"fat": 0.29,
"saturatedFat": 0.048,
"monounsaturatedFat": 0.114,
"polyunsaturatedFat": 0.04,
"carbs": 23.64,
"sugar": 0,
"fiber": 4.4,
"protein": 2.06,
"sodium": 9,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.11,
"vitaminB2": 0.113,
"vitaminB3": 0.883,
"vitaminB5": 0.226,
"vitaminB6": 0.2,
"vitaminB9": 14,
"vitaminB12": 0,
"vitaminC": 36.3,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 21,
"calcium": 24,
"phosphorus": 32,
"potassium": 247,
"iron": 0.6,
"selenium": 0.6,
"zinc": 0.1,
"manganese": 0,
"copper": 0.086,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 250
}
},
{
"id": 924,
"name": "Figs",
"categoryId": 900,
"energy": 74,
"fat": 0.3,
"saturatedFat": 0.06,
"monounsaturatedFat": 0.066,
"polyunsaturatedFat": 0.144,
"carbs": 19.18,
"sugar": 16.26,
"fiber": 2.9,
"protein": 0.75,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 7,
"vitaminB1": 0.06,
"vitaminB2": 0.05,
"vitaminB3": 0.4,
"vitaminB5": 0.3,
"vitaminB6": 0.113,
"vitaminB9": 6,
"vitaminB12": 0,
"vitaminC": 2,
"vitaminD": 0,
"vitaminE": 0.11,
"vitaminK": 4.7,
"magnesium": 17,
"calcium": 35,
"phosphorus": 14,
"potassium": 232,
"iron": 0.37,
"selenium": 0.2,
"zinc": 0.15,
"manganese": 0.128,
"copper": 0.07,
"choline": 4.7
},
{
"id": 925,
"name": "Medjool Dates",
"categoryId": 900,
"energy": 277,
"fat": 0.15,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 74.97,
"sugar": 66.47,
"fiber": 6.7,
"protein": 1.81,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 7,
"vitaminB1": 0.05,
"vitaminB2": 0.06,
"vitaminB3": 1.61,
"vitaminB5": 0.805,
"vitaminB6": 0.249,
"vitaminB9": 15,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 2.7,
"magnesium": 54,
"calcium": 64,
"phosphorus": 62,
"potassium": 696,
"iron": 0.9,
"selenium": 0,
"zinc": 0.44,
"manganese": 0.296,
"copper": 0.362,
"choline": 9.9
},
{
"id": 926,
"name": "Apricots",
"categoryId": 900,
"energy": 48,
"fat": 0.39,
"saturatedFat": 0.027,
"monounsaturatedFat": 0.17,
"polyunsaturatedFat": 0.077,
"carbs": 11.12,
"sugar": 9.24,
"fiber": 2,
"protein": 1.4,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 96,
"vitaminB1": 0.03,
"vitaminB2": 0.04,
"vitaminB3": 0.6,
"vitaminB5": 0.24,
"vitaminB6": 0.054,
"vitaminB9": 9,
"vitaminB12": 0,
"vitaminC": 10,
"vitaminD": 0,
"vitaminE": 0.89,
"vitaminK": 3.3,
"magnesium": 10,
"calcium": 13,
"phosphorus": 23,
"potassium": 259,
"iron": 0.39,
"selenium": 0.1,
"zinc": 0.2,
"manganese": 0.077,
"copper": 0.078,
"choline": 2.8,
"volume": {
"portionId": "cups",
"weightInGrams": 155
}
},
{
"id": 927,
"name": "Pomegranates",
"categoryId": 900,
"energy": 83,
"fat": 1.17,
"saturatedFat": 0.12,
"monounsaturatedFat": 0.093,
"polyunsaturatedFat": 0.079,
"carbs": 18.7,
"sugar": 13.67,
"fiber": 4,
"protein": 1.67,
"sodium": 3,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.067,
"vitaminB2": 0.053,
"vitaminB3": 0.293,
"vitaminB5": 0.377,
"vitaminB6": 0.075,
"vitaminB9": 38,
"vitaminB12": 0,
"vitaminC": 10.2,
"vitaminD": 0,
"vitaminE": 0.6,
"vitaminK": 16.4,
"magnesium": 12,
"calcium": 10,
"phosphorus": 36,
"potassium": 236,
"iron": 0.3,
"selenium": 0.5,
"zinc": 0.35,
"manganese": 0.119,
"copper": 0.158,
"choline": 7.6,
"volume": {
"portionId": "cups",
"weightInGrams": 87
}
},
{
"id": 928,
"name": "Watermelon",
"categoryId": 900,
"energy": 30,
"fat": 0.15,
"saturatedFat": 0.016,
"monounsaturatedFat": 0.037,
"polyunsaturatedFat": 0.05,
"carbs": 7.55,
"sugar": 6.2,
"fiber": 0.4,
"protein": 0.61,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 28,
"vitaminB1": 0.033,
"vitaminB2": 0.021,
"vitaminB3": 0.178,
"vitaminB5": 0.221,
"vitaminB6": 0.045,
"vitaminB9": 3,
"vitaminB12": 0,
"vitaminC": 8.1,
"vitaminD": 0,
"vitaminE": 0.05,
"vitaminK": 0.1,
"magnesium": 10,
"calcium": 7,
"phosphorus": 11,
"potassium": 112,
"iron": 0.24,
"selenium": 0.4,
"zinc": 0.1,
"manganese": 0.038,
"copper": 0.042,
"choline": 4.1,
"volume": {
"portionId": "cups",
"weightInGrams": 152
}
},
{
"id": 929,
"name": "Canteloupe Melons",
"categoryId": 900,
"energy": 34,
"fat": 0.19,
"saturatedFat": 0.051,
"monounsaturatedFat": 0.003,
"polyunsaturatedFat": 0.081,
"carbs": 8.16,
"sugar": 7.86,
"fiber": 0.9,
"protein": 0.84,
"sodium": 16,
"cholesterol": 0,
"vitaminA": 169,
"vitaminB1": 0.041,
"vitaminB2": 0.019,
"vitaminB3": 0.734,
"vitaminB5": 0.105,
"vitaminB6": 0.072,
"vitaminB9": 21,
"vitaminB12": 0,
"vitaminC": 36.7,
"vitaminD": 0,
"vitaminE": 0.05,
"vitaminK": 2.5,
"magnesium": 12,
"calcium": 9,
"phosphorus": 15,
"potassium": 267,
"iron": 0.21,
"selenium": 0.4,
"zinc": 0.18,
"manganese": 0.041,
"copper": 0.041,
"choline": 7.6,
"volume": {
"portionId": "cups",
"weightInGrams": 160
}
},
{
"id": 930,
"name": "Papayas",
"categoryId": 900,
"energy": 43,
"fat": 0.26,
"saturatedFat": 0.081,
"monounsaturatedFat": 0.072,
"polyunsaturatedFat": 0.058,
"carbs": 10.82,
"sugar": 7.82,
"fiber": 1.7,
"protein": 0.47,
"sodium": 8,
"cholesterol": 0,
"vitaminA": 47,
"vitaminB1": 0.023,
"vitaminB2": 0.027,
"vitaminB3": 0.357,
"vitaminB5": 0.191,
"vitaminB6": 0.038,
"vitaminB9": 37,
"vitaminB12": 0,
"vitaminC": 60.9,
"vitaminD": 0,
"vitaminE": 0.3,
"vitaminK": 2.6,
"magnesium": 21,
"calcium": 20,
"phosphorus": 10,
"potassium": 182,
"iron": 0.25,
"selenium": 0.6,
"zinc": 0.08,
"manganese": 0.04,
"copper": 0.045,
"choline": 6.1,
"volume": {
"portionId": "cups",
"weightInGrams": 230
}
},
{
"id": 931,
"name": "Limes",
"categoryId": 900,
"energy": 30,
"fat": 0.2,
"saturatedFat": 0.022,
"monounsaturatedFat": 0.019,
"polyunsaturatedFat": 0.055,
"carbs": 10.54,
"sugar": 1.69,
"fiber": 2.8,
"protein": 0.7,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 2,
"vitaminB1": 0.03,
"vitaminB2": 0.02,
"vitaminB3": 0.2,
"vitaminB5": 0.217,
"vitaminB6": 0.043,
"vitaminB9": 8,
"vitaminB12": 0,
"vitaminC": 29.1,
"vitaminD": 0,
"vitaminE": 0.22,
"vitaminK": 0.6,
"magnesium": 6,
"calcium": 33,
"phosphorus": 18,
"potassium": 102,
"iron": 0.6,
"selenium": 0.4,
"zinc": 0.11,
"manganese": 0.008,
"copper": 0.065,
"choline": 5.1
},
{
"id": 932,
"name": "Nectarines",
"categoryId": 900,
"energy": 44,
"fat": 0.32,
"saturatedFat": 0.025,
"monounsaturatedFat": 0.088,
"polyunsaturatedFat": 0.113,
"carbs": 10.55,
"sugar": 7.89,
"fiber": 1.7,
"protein": 1.06,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 17,
"vitaminB1": 0.034,
"vitaminB2": 0.027,
"vitaminB3": 1.125,
"vitaminB5": 0.185,
"vitaminB6": 0.025,
"vitaminB9": 5,
"vitaminB12": 0,
"vitaminC": 5.4,
"vitaminD": 0,
"vitaminE": 0.77,
"vitaminK": 2.2,
"magnesium": 9,
"calcium": 6,
"phosphorus": 26,
"potassium": 201,
"iron": 0.28,
"selenium": 0,
"zinc": 0.17,
"manganese": 0.054,
"copper": 0.086,
"choline": 6.2,
"volume": {
"portionId": "cups",
"weightInGrams": 143
}
},
{
"id": 933,
"name": "Lemons",
"categoryId": 900,
"energy": 29,
"fat": 0.3,
"saturatedFat": 0.039,
"monounsaturatedFat": 0.011,
"polyunsaturatedFat": 0.089,
"carbs": 9.32,
"sugar": 2.5,
"fiber": 2.8,
"protein": 1.1,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.04,
"vitaminB2": 0.02,
"vitaminB3": 0.1,
"vitaminB5": 0.19,
"vitaminB6": 0.08,
"vitaminB9": 11,
"vitaminB12": 0,
"vitaminC": 53,
"vitaminD": 0,
"vitaminE": 0.15,
"vitaminK": 0,
"magnesium": 8,
"calcium": 26,
"phosphorus": 16,
"potassium": 138,
"iron": 0.6,
"selenium": 0.4,
"zinc": 0.06,
"manganese": 0.03,
"copper": 0.037,
"choline": 5.1,
"volume": {
"portionId": "cups",
"weightInGrams": 212
}
}
]
================================================
FILE: src/foods/builtIn/grainsAndPasta.json
================================================
[
{
"id": 601,
"name": "Brown Rice",
"categoryId": 600,
"energy": 367,
"fat": 3.2,
"saturatedFat": 0.591,
"monounsaturatedFat": 1.054,
"polyunsaturatedFat": 1,
"carbs": 76.25,
"sugar": 0.66,
"fiber": 3.6,
"protein": 7.54,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.541,
"vitaminB2": 0.095,
"vitaminB3": 6.494,
"vitaminB5": 1.065,
"vitaminB6": 0.477,
"vitaminB9": 23,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.6,
"vitaminK": 0.6,
"magnesium": 116,
"calcium": 9,
"phosphorus": 311,
"potassium": 250,
"iron": 1.29,
"selenium": 17.1,
"zinc": 2.13,
"manganese": 2.853,
"copper": 0.302,
"choline": 21.5,
"volume": {
"portionId": "cups",
"weightInGrams": 185
}
},
{
"id": 602,
"name": "White Rice",
"categoryId": 600,
"energy": 360,
"fat": 0.58,
"saturatedFat": 0.158,
"monounsaturatedFat": 0.181,
"polyunsaturatedFat": 0.155,
"carbs": 79.34,
"sugar": 0,
"fiber": 0,
"protein": 6.61,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.07,
"vitaminB2": 0.048,
"vitaminB3": 1.6,
"vitaminB5": 1.342,
"vitaminB6": 0.145,
"vitaminB9": 9,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 35,
"calcium": 9,
"phosphorus": 108,
"potassium": 86,
"iron": 0.8,
"selenium": 0,
"zinc": 1.16,
"manganese": 1.1,
"copper": 0.11,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 195
}
},
{
"id": 603,
"name": "Oats",
"categoryId": 600,
"energy": 379,
"fat": 6.52,
"saturatedFat": 1.11,
"monounsaturatedFat": 1.98,
"polyunsaturatedFat": 2.3,
"carbs": 67.7,
"sugar": 0.99,
"fiber": 10.1,
"protein": 13.15,
"sodium": 6,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.46,
"vitaminB2": 0.155,
"vitaminB3": 1.125,
"vitaminB5": 1.12,
"vitaminB6": 0.1,
"vitaminB9": 32,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.42,
"vitaminK": 2,
"magnesium": 138,
"calcium": 52,
"phosphorus": 410,
"potassium": 362,
"iron": 4.25,
"selenium": 28.9,
"zinc": 3.64,
"manganese": 3.63,
"copper": 0.391,
"choline": 40.4,
"volume": {
"portionId": "cups",
"weightInGrams": 81
}
},
{
"id": 604,
"name": "Cornstarch",
"categoryId": 600,
"energy": 381,
"fat": 0.05,
"saturatedFat": 0.009,
"monounsaturatedFat": 0.016,
"polyunsaturatedFat": 0.025,
"carbs": 91.27,
"sugar": 0,
"fiber": 0.9,
"protein": 0.26,
"sodium": 9,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 3,
"calcium": 2,
"phosphorus": 13,
"potassium": 3,
"iron": 0.47,
"selenium": 2.8,
"zinc": 0.06,
"manganese": 0.053,
"copper": 0.05,
"choline": 0.4,
"volume": {
"portionId": "cups",
"weightInGrams": 128
}
},
{
"id": 605,
"name": "Whole-wheat Pasta",
"categoryId": 600,
"energy": 352,
"fat": 2.93,
"saturatedFat": 0.428,
"monounsaturatedFat": 0.361,
"polyunsaturatedFat": 1.136,
"carbs": 73.37,
"sugar": 2.74,
"fiber": 9.2,
"protein": 13.87,
"sodium": 6,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.407,
"vitaminB2": 0.218,
"vitaminB3": 8.691,
"vitaminB5": 0.87,
"vitaminB6": 0.283,
"vitaminB9": 69,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.46,
"vitaminK": 1.4,
"magnesium": 128,
"calcium": 29,
"phosphorus": 343,
"potassium": 434,
"iron": 3.62,
"selenium": 77.6,
"zinc": 2.97,
"manganese": 2.983,
"copper": 0.497,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 96
}
},
{
"id": 606,
"name": "Pasta",
"categoryId": 600,
"energy": 371,
"fat": 1.51,
"saturatedFat": 0.277,
"monounsaturatedFat": 0.171,
"polyunsaturatedFat": 0.564,
"carbs": 74.67,
"sugar": 2.67,
"fiber": 3.2,
"protein": 13.04,
"sodium": 6,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.09,
"vitaminB2": 0.06,
"vitaminB3": 1.7,
"vitaminB5": 0.431,
"vitaminB6": 0.142,
"vitaminB9": 18,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.11,
"vitaminK": 0.1,
"magnesium": 53,
"calcium": 21,
"phosphorus": 189,
"potassium": 223,
"iron": 1.3,
"selenium": 63.2,
"zinc": 1.41,
"manganese": 0.917,
"copper": 0.289,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 96
}
},
{
"id": 607,
"name": "Quinoa",
"categoryId": 600,
"energy": 368,
"fat": 6.07,
"saturatedFat": 0.706,
"monounsaturatedFat": 1.613,
"polyunsaturatedFat": 3.292,
"carbs": 64.16,
"sugar": 0,
"fiber": 7,
"protein": 14.12,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.36,
"vitaminB2": 0.318,
"vitaminB3": 1.52,
"vitaminB5": 0.772,
"vitaminB6": 0.487,
"vitaminB9": 184,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 2.44,
"vitaminK": 0,
"magnesium": 197,
"calcium": 47,
"phosphorus": 457,
"potassium": 563,
"iron": 4.57,
"selenium": 8.5,
"zinc": 3.1,
"manganese": 2.033,
"copper": 0.59,
"choline": 70.2,
"volume": {
"portionId": "cups",
"weightInGrams": 170
}
},
{
"id": 608,
"name": "Egg Pasta",
"categoryId": 600,
"energy": 130,
"fat": 1.74,
"saturatedFat": 0.408,
"monounsaturatedFat": 0.508,
"polyunsaturatedFat": 0.521,
"carbs": 23.54,
"sugar": 0,
"fiber": 0,
"protein": 5.28,
"sodium": 83,
"cholesterol": 41,
"vitaminA": 17,
"vitaminB1": 0.173,
"vitaminB2": 0.174,
"vitaminB3": 1.257,
"vitaminB5": 0.231,
"vitaminB6": 0.037,
"vitaminB9": 43,
"vitaminB12": 0.1,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 14,
"calcium": 10,
"phosphorus": 52,
"potassium": 21,
"iron": 1.16,
"selenium": 0,
"zinc": 0.44,
"manganese": 0.183,
"copper": 0.056,
"choline": 0
},
{
"id": 609,
"name": "Egg Noodles",
"categoryId": 600,
"energy": 384,
"fat": 4.44,
"saturatedFat": 1.18,
"monounsaturatedFat": 1.252,
"polyunsaturatedFat": 1.331,
"carbs": 71.27,
"sugar": 1.88,
"fiber": 3.3,
"protein": 14.16,
"sodium": 21,
"cholesterol": 84,
"vitaminA": 17,
"vitaminB1": 0.17,
"vitaminB2": 0.09,
"vitaminB3": 2.1,
"vitaminB5": 0.912,
"vitaminB6": 0.216,
"vitaminB9": 29,
"vitaminB12": 0.29,
"vitaminC": 0,
"vitaminD": 0.3,
"vitaminE": 0.37,
"vitaminK": 0.5,
"magnesium": 58,
"calcium": 35,
"phosphorus": 241,
"potassium": 244,
"iron": 1.9,
"selenium": 78.8,
"zinc": 1.92,
"manganese": 0.855,
"copper": 0.297,
"choline": 78.7,
"volume": {
"portionId": "cups",
"weightInGrams": 38
}
},
{
"id": 610,
"name": "Couscous",
"categoryId": 600,
"energy": 376,
"fat": 0.64,
"saturatedFat": 0.117,
"monounsaturatedFat": 0.089,
"polyunsaturatedFat": 0.252,
"carbs": 77.43,
"sugar": 0,
"fiber": 5,
"protein": 12.76,
"sodium": 10,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.163,
"vitaminB2": 0.078,
"vitaminB3": 3.49,
"vitaminB5": 1.243,
"vitaminB6": 0.11,
"vitaminB9": 20,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 44,
"calcium": 24,
"phosphorus": 170,
"potassium": 166,
"iron": 1.08,
"selenium": 0,
"zinc": 0.83,
"manganese": 0.78,
"copper": 0.247,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 173
}
},
{
"id": 611,
"name": "Toasted Wheat Germ",
"categoryId": 600,
"energy": 382,
"fat": 10.7,
"saturatedFat": 1.83,
"monounsaturatedFat": 1.5,
"polyunsaturatedFat": 6.62,
"carbs": 49.6,
"sugar": 7.8,
"fiber": 15.1,
"protein": 29.1,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 5,
"vitaminB1": 1.67,
"vitaminB2": 0.82,
"vitaminB3": 5.59,
"vitaminB5": 1.387,
"vitaminB6": 0.978,
"vitaminB9": 352,
"vitaminB12": 0,
"vitaminC": 6,
"vitaminD": 0,
"vitaminE": 15.99,
"vitaminK": 4,
"magnesium": 320,
"calcium": 45,
"phosphorus": 1146,
"potassium": 947,
"iron": 9.09,
"selenium": 65,
"zinc": 16.67,
"manganese": 19.956,
"copper": 0.62,
"choline": 178.6,
"volume": {
"portionId": "cups",
"weightInGrams": 113
}
},
{
"id": 612,
"name": "White Flour",
"categoryId": 600,
"energy": 361,
"fat": 1.66,
"saturatedFat": 0.244,
"monounsaturatedFat": 0.14,
"polyunsaturatedFat": 0.727,
"carbs": 72.53,
"sugar": 0.31,
"fiber": 2.4,
"protein": 11.98,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.812,
"vitaminB2": 0.512,
"vitaminB3": 7.554,
"vitaminB5": 0.438,
"vitaminB6": 0.037,
"vitaminB9": 183,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.4,
"vitaminK": 0.3,
"magnesium": 25,
"calcium": 15,
"phosphorus": 97,
"potassium": 100,
"iron": 4.41,
"selenium": 39.7,
"zinc": 0.85,
"manganese": 0.792,
"copper": 0.182,
"choline": 10.4,
"volume": {
"portionId": "cups",
"weightInGrams": 137
}
},
{
"id": 613,
"name": "Bulgur",
"categoryId": 600,
"energy": 342,
"fat": 1.33,
"saturatedFat": 0.232,
"monounsaturatedFat": 0.173,
"polyunsaturatedFat": 0.541,
"carbs": 75.87,
"sugar": 0.41,
"fiber": 12.5,
"protein": 12.29,
"sodium": 17,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.232,
"vitaminB2": 0.115,
"vitaminB3": 5.114,
"vitaminB5": 1.045,
"vitaminB6": 0.342,
"vitaminB9": 27,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.06,
"vitaminK": 1.9,
"magnesium": 164,
"calcium": 35,
"phosphorus": 300,
"potassium": 410,
"iron": 2.46,
"selenium": 2.3,
"zinc": 1.93,
"manganese": 3.048,
"copper": 0.335,
"choline": 28.1,
"volume": {
"portionId": "cups",
"weightInGrams": 140
}
},
{
"id": 614,
"name": "Buckwheat",
"categoryId": 600,
"energy": 343,
"fat": 3.4,
"saturatedFat": 0.741,
"monounsaturatedFat": 1.04,
"polyunsaturatedFat": 1.039,
"carbs": 71.5,
"sugar": 0,
"fiber": 10,
"protein": 13.25,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.101,
"vitaminB2": 0.425,
"vitaminB3": 7.02,
"vitaminB5": 1.233,
"vitaminB6": 0.21,
"vitaminB9": 30,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 231,
"calcium": 18,
"phosphorus": 347,
"potassium": 460,
"iron": 2.2,
"selenium": 8.3,
"zinc": 2.4,
"manganese": 1.3,
"copper": 1.1,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 170
}
},
{
"id": 615,
"name": "Millet",
"categoryId": 600,
"energy": 378,
"fat": 4.22,
"saturatedFat": 0.723,
"monounsaturatedFat": 0.773,
"polyunsaturatedFat": 2.134,
"carbs": 72.85,
"sugar": 0,
"fiber": 8.5,
"protein": 11.02,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.421,
"vitaminB2": 0.29,
"vitaminB3": 4.72,
"vitaminB5": 0.848,
"vitaminB6": 0.384,
"vitaminB9": 85,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.05,
"vitaminK": 0.9,
"magnesium": 114,
"calcium": 8,
"phosphorus": 285,
"potassium": 195,
"iron": 3.01,
"selenium": 2.7,
"zinc": 1.68,
"manganese": 1.632,
"copper": 0.75,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 200
}
},
{
"id": 616,
"name": "Whole-wheat Pasta",
"categoryId": 600,
"energy": 352,
"fat": 2.93,
"saturatedFat": 0.428,
"monounsaturatedFat": 0.361,
"polyunsaturatedFat": 1.136,
"carbs": 73.37,
"sugar": 2.74,
"fiber": 9.2,
"protein": 13.87,
"sodium": 6,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.407,
"vitaminB2": 0.218,
"vitaminB3": 8.691,
"vitaminB5": 0.87,
"vitaminB6": 0.283,
"vitaminB9": 69,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.46,
"vitaminK": 1.4,
"magnesium": 128,
"calcium": 29,
"phosphorus": 343,
"potassium": 434,
"iron": 3.62,
"selenium": 77.6,
"zinc": 2.97,
"manganese": 2.983,
"copper": 0.497,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 96
}
},
{
"id": 617,
"name": "Cornstarch",
"categoryId": 600,
"energy": 381,
"fat": 0.05,
"saturatedFat": 0.009,
"monounsaturatedFat": 0.016,
"polyunsaturatedFat": 0.025,
"carbs": 91.27,
"sugar": 0,
"fiber": 0.9,
"protein": 0.26,
"sodium": 9,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 3,
"calcium": 2,
"phosphorus": 13,
"potassium": 3,
"iron": 0.47,
"selenium": 2.8,
"zinc": 0.06,
"manganese": 0.053,
"copper": 0.05,
"choline": 0.4,
"volume": {
"portionId": "cups",
"weightInGrams": 128
}
},
{
"id": 618,
"name": "Whole-Grain Flour",
"categoryId": 600,
"energy": 340,
"fat": 2.5,
"saturatedFat": 0.43,
"monounsaturatedFat": 0.283,
"polyunsaturatedFat": 1.167,
"carbs": 71.97,
"sugar": 0.41,
"fiber": 10.7,
"protein": 13.21,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.502,
"vitaminB2": 0.165,
"vitaminB3": 4.957,
"vitaminB5": 0.603,
"vitaminB6": 0.407,
"vitaminB9": 44,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.71,
"vitaminK": 1.9,
"magnesium": 137,
"calcium": 34,
"phosphorus": 357,
"potassium": 363,
"iron": 3.6,
"selenium": 61.8,
"zinc": 2.6,
"manganese": 4.067,
"copper": 0.41,
"choline": 31.2,
"volume": {
"portionId": "cups",
"weightInGrams": 120
}
},
{
"id": 619,
"name": "Oat Flour",
"categoryId": 600,
"energy": 404,
"fat": 9.12,
"saturatedFat": 1.607,
"monounsaturatedFat": 2.866,
"polyunsaturatedFat": 3.329,
"carbs": 65.7,
"sugar": 0.8,
"fiber": 6.5,
"protein": 14.66,
"sodium": 19,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.692,
"vitaminB2": 0.125,
"vitaminB3": 1.474,
"vitaminB5": 0.201,
"vitaminB6": 0.125,
"vitaminB9": 32,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.7,
"vitaminK": 3.2,
"magnesium": 144,
"calcium": 55,
"phosphorus": 452,
"potassium": 371,
"iron": 4,
"selenium": 34,
"zinc": 3.2,
"manganese": 4.019,
"copper": 0.437,
"choline": 29.9,
"volume": {
"portionId": "cups",
"weightInGrams": 104
}
},
{
"id": 620,
"name": "Rice Noodles",
"categoryId": 600,
"energy": 364,
"fat": 0.56,
"saturatedFat": 0.153,
"monounsaturatedFat": 0.175,
"polyunsaturatedFat": 0.15,
"carbs": 80.18,
"sugar": 0.12,
"fiber": 1.6,
"protein": 5.95,
"sodium": 182,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.031,
"vitaminB2": 0.017,
"vitaminB3": 0.221,
"vitaminB5": 0.051,
"vitaminB6": 0.015,
"vitaminB9": 3,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.11,
"vitaminK": 0,
"magnesium": 12,
"calcium": 18,
"phosphorus": 153,
"potassium": 30,
"iron": 0.7,
"selenium": 15.1,
"zinc": 0.74,
"manganese": 0.498,
"copper": 0.078,
"choline": 5.5
}
]
================================================
FILE: src/foods/builtIn/index.ts
================================================
import poultry from './poultry.json'
import beef from './beef.json'
import pork from './pork.json'
import finfishAndShellfish from './finfishAndShellFish.json'
import dairyAndEggs from './dairyAndEggs.json'
import grainsAndPasta from './grainsAndPasta.json'
import vegetables from './vegetables.json'
import legumesAndLegumeProducts from './legumesAndLegumeProducts.json'
import fruitsAndJuices from './fruitsAndJuices.json'
import nutAndSeedProducts from './nutAndSeedProducts.json'
import fatsAndOils from './fatsAndOils.json'
import bakedProducts from './bakedProducts.json'
import saucesAndSoups from './saucesAndSoups.json'
import spicesAndHerbs from './spicesAndHerbs.json'
import sweetsAndSnacks from './sweetsAndSnacks.json'
import beverages from './beverages.json'
const foods = [
...poultry,
...beef,
...pork,
...finfishAndShellfish,
...dairyAndEggs,
...grainsAndPasta,
...vegetables,
...legumesAndLegumeProducts,
...fruitsAndJuices,
...nutAndSeedProducts,
...fatsAndOils,
...bakedProducts,
...saucesAndSoups,
...spicesAndHerbs,
...sweetsAndSnacks,
...beverages,
]
export default foods
================================================
FILE: src/foods/builtIn/legumesAndLegumeProducts.json
================================================
[
{
"id": 801,
"name": "Traditional Refried Beans (canned)",
"categoryId": 800,
"energy": 90,
"fat": 2.01,
"saturatedFat": 0.631,
"monounsaturatedFat": 0.601,
"polyunsaturatedFat": 0.543,
"carbs": 13.55,
"sugar": 0.54,
"fiber": 3.7,
"protein": 4.98,
"sodium": 370,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.076,
"vitaminB2": 0.079,
"vitaminB3": 0.367,
"vitaminB5": 0.189,
"vitaminB6": 0.103,
"vitaminB9": 11,
"vitaminB12": 0,
"vitaminC": 6,
"vitaminD": 0,
"vitaminE": 0.09,
"vitaminK": 2.1,
"magnesium": 35,
"calcium": 29,
"phosphorus": 92,
"potassium": 319,
"iron": 1.44,
"selenium": 5.8,
"zinc": 0.58,
"manganese": 0.289,
"copper": 0.129,
"choline": 21.2,
"volume": {
"portionId": "cups",
"weightInGrams": 238
}
},
{
"id": 802,
"name": "Pinto Beans (canned)",
"categoryId": 800,
"energy": 114,
"fat": 0.9,
"saturatedFat": 0.158,
"monounsaturatedFat": 0.153,
"polyunsaturatedFat": 0.273,
"carbs": 20.22,
"sugar": 0.54,
"fiber": 5.5,
"protein": 6.99,
"sodium": 239,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.052,
"vitaminB2": 0.019,
"vitaminB3": 0.272,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 24,
"vitaminB12": 0,
"vitaminC": 0.1,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 32,
"calcium": 63,
"phosphorus": 101,
"potassium": 274,
"iron": 1.33,
"selenium": 0,
"zinc": 0.61,
"manganese": 0.383,
"copper": 0.259,
"choline": 0
},
{
"id": 803,
"name": "Peanut Butter",
"categoryId": 800,
"energy": 590,
"fat": 49.9,
"saturatedFat": 7.716,
"monounsaturatedFat": 23.582,
"polyunsaturatedFat": 14.363,
"carbs": 21.83,
"sugar": 9.29,
"fiber": 6.6,
"protein": 24,
"sodium": 203,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.12,
"vitaminB2": 0.11,
"vitaminB3": 13.69,
"vitaminB5": 0,
"vitaminB6": 0.45,
"vitaminB9": 92,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 9.05,
"vitaminK": 0.6,
"magnesium": 159,
"calcium": 41,
"phosphorus": 317,
"potassium": 747,
"iron": 1.9,
"selenium": 7.5,
"zinc": 2.78,
"manganese": 0,
"copper": 0.515,
"choline": 63.5,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 16
}
},
{
"id": 804,
"name": "Chickpeas (canned)",
"categoryId": 800,
"energy": 139,
"fat": 2.77,
"saturatedFat": 0.214,
"monounsaturatedFat": 0.488,
"polyunsaturatedFat": 0.967,
"carbs": 22.53,
"sugar": 4.01,
"fiber": 6.4,
"protein": 7.05,
"sodium": 246,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.027,
"vitaminB2": 0.015,
"vitaminB3": 0.14,
"vitaminB5": 0,
"vitaminB6": 0.116,
"vitaminB9": 48,
"vitaminB12": 0,
"vitaminC": 0.1,
"vitaminD": 0,
"vitaminE": 0.29,
"vitaminK": 3.4,
"magnesium": 26,
"calcium": 45,
"phosphorus": 85,
"potassium": 126,
"iron": 1.07,
"selenium": 3.1,
"zinc": 0.63,
"manganese": 0.846,
"copper": 0.253,
"choline": 0
},
{
"id": 805,
"name": "Pinto Beans",
"categoryId": 800,
"energy": 347,
"fat": 1.23,
"saturatedFat": 0.235,
"monounsaturatedFat": 0.229,
"polyunsaturatedFat": 0.407,
"carbs": 62.55,
"sugar": 2.11,
"fiber": 15.5,
"protein": 21.42,
"sodium": 12,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.713,
"vitaminB2": 0.212,
"vitaminB3": 1.174,
"vitaminB5": 0.785,
"vitaminB6": 0.474,
"vitaminB9": 525,
"vitaminB12": 0,
"vitaminC": 6.3,
"vitaminD": 0,
"vitaminE": 0.21,
"vitaminK": 5.6,
"magnesium": 176,
"calcium": 113,
"phosphorus": 411,
"potassium": 1393,
"iron": 5.07,
"selenium": 27.9,
"zinc": 2.28,
"manganese": 1.148,
"copper": 0.893,
"choline": 66.2,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 12
}
},
{
"id": 806,
"name": "White Beans",
"categoryId": 800,
"energy": 333,
"fat": 0.85,
"saturatedFat": 0.219,
"monounsaturatedFat": 0.074,
"polyunsaturatedFat": 0.364,
"carbs": 60.27,
"sugar": 2.11,
"fiber": 15.2,
"protein": 23.36,
"sodium": 16,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.437,
"vitaminB2": 0.146,
"vitaminB3": 0.479,
"vitaminB5": 0.732,
"vitaminB6": 0.318,
"vitaminB9": 388,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.21,
"vitaminK": 5.6,
"magnesium": 190,
"calcium": 240,
"phosphorus": 301,
"potassium": 1795,
"iron": 10.44,
"selenium": 12.8,
"zinc": 3.67,
"manganese": 1.796,
"copper": 0.984,
"choline": 66.2,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 12.6
}
},
{
"id": 807,
"name": "Red Beans",
"categoryId": 800,
"energy": 337,
"fat": 1.06,
"saturatedFat": 0.154,
"monounsaturatedFat": 0.082,
"polyunsaturatedFat": 0.586,
"carbs": 61.29,
"sugar": 2.1,
"fiber": 15.2,
"protein": 22.53,
"sodium": 12,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.608,
"vitaminB2": 0.215,
"vitaminB3": 2.11,
"vitaminB5": 0.78,
"vitaminB6": 0.397,
"vitaminB9": 394,
"vitaminB12": 0,
"vitaminC": 4.5,
"vitaminD": 0,
"vitaminE": 0.21,
"vitaminK": 5.6,
"magnesium": 138,
"calcium": 83,
"phosphorus": 406,
"potassium": 1359,
"iron": 6.69,
"selenium": 3.2,
"zinc": 2.79,
"manganese": 1.111,
"copper": 0.699,
"choline": 65.9,
"volume": {
"portionId": "cups",
"weightInGrams": 184
}
},
{
"id": 808,
"name": "Black Beans",
"categoryId": 800,
"energy": 341,
"fat": 1.42,
"saturatedFat": 0.366,
"monounsaturatedFat": 0.123,
"polyunsaturatedFat": 0.61,
"carbs": 62.36,
"sugar": 2.12,
"fiber": 15.5,
"protein": 21.6,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.9,
"vitaminB2": 0.193,
"vitaminB3": 1.955,
"vitaminB5": 0.899,
"vitaminB6": 0.286,
"vitaminB9": 444,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.21,
"vitaminK": 5.6,
"magnesium": 171,
"calcium": 123,
"phosphorus": 352,
"potassium": 1483,
"iron": 5.02,
"selenium": 3.2,
"zinc": 3.65,
"manganese": 1.06,
"copper": 0.841,
"choline": 66.4,
"volume": {
"portionId": "cups",
"weightInGrams": 194
}
},
{
"id": 809,
"name": "Adzuki Beans",
"categoryId": 800,
"energy": 329,
"fat": 0.53,
"saturatedFat": 0.191,
"monounsaturatedFat": 0.05,
"polyunsaturatedFat": 0.113,
"carbs": 62.9,
"sugar": 0,
"fiber": 12.7,
"protein": 19.87,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.455,
"vitaminB2": 0.22,
"vitaminB3": 2.63,
"vitaminB5": 1.471,
"vitaminB6": 0.351,
"vitaminB9": 622,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 127,
"calcium": 66,
"phosphorus": 381,
"potassium": 1254,
"iron": 4.98,
"selenium": 3.1,
"zinc": 5.04,
"manganese": 1.73,
"copper": 1.094,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 197
}
},
{
"id": 810,
"name": "Lima Beans",
"categoryId": 800,
"energy": 338,
"fat": 0.69,
"saturatedFat": 0.161,
"monounsaturatedFat": 0.062,
"polyunsaturatedFat": 0.309,
"carbs": 63.38,
"sugar": 8.5,
"fiber": 19,
"protein": 21.46,
"sodium": 18,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.507,
"vitaminB2": 0.202,
"vitaminB3": 1.537,
"vitaminB5": 1.355,
"vitaminB6": 0.512,
"vitaminB9": 395,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.72,
"vitaminK": 6,
"magnesium": 224,
"calcium": 81,
"phosphorus": 385,
"potassium": 1724,
"iron": 7.51,
"selenium": 7.2,
"zinc": 2.83,
"manganese": 1.672,
"copper": 0.74,
"choline": 96.7,
"volume": {
"portionId": "cups",
"weightInGrams": 178
}
},
{
"id": 811,
"name": "Kidney Beans",
"categoryId": 800,
"energy": 333,
"fat": 0.83,
"saturatedFat": 0.12,
"monounsaturatedFat": 0.064,
"polyunsaturatedFat": 0.457,
"carbs": 60.01,
"sugar": 2.23,
"fiber": 24.9,
"protein": 23.58,
"sodium": 24,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.529,
"vitaminB2": 0.219,
"vitaminB3": 2.06,
"vitaminB5": 0.78,
"vitaminB6": 0.397,
"vitaminB9": 394,
"vitaminB12": 0,
"vitaminC": 4.5,
"vitaminD": 0,
"vitaminE": 0.22,
"vitaminK": 19,
"magnesium": 140,
"calcium": 143,
"phosphorus": 407,
"potassium": 1406,
"iron": 8.2,
"selenium": 3.2,
"zinc": 2.79,
"manganese": 1.021,
"copper": 0.958,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 184
}
},
{
"id": 812,
"name": "Soybeans",
"categoryId": 800,
"energy": 446,
"fat": 19.94,
"saturatedFat": 2.884,
"monounsaturatedFat": 4.404,
"polyunsaturatedFat": 11.255,
"carbs": 30.16,
"sugar": 7.33,
"fiber": 9.3,
"protein": 36.49,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.874,
"vitaminB2": 0.87,
"vitaminB3": 1.623,
"vitaminB5": 0.793,
"vitaminB6": 0.377,
"vitaminB9": 375,
"vitaminB12": 0,
"vitaminC": 6,
"vitaminD": 0,
"vitaminE": 0.85,
"vitaminK": 47,
"magnesium": 280,
"calcium": 277,
"phosphorus": 704,
"potassium": 1797,
"iron": 15.7,
"selenium": 17.8,
"zinc": 4.89,
"manganese": 2.517,
"copper": 1.658,
"choline": 115.9,
"volume": {
"portionId": "cups",
"weightInGrams": 186
}
},
{
"id": 813,
"name": "Hummus",
"categoryId": 800,
"energy": 237,
"fat": 17.82,
"saturatedFat": 2.562,
"monounsaturatedFat": 5.34,
"polyunsaturatedFat": 8.812,
"carbs": 15,
"sugar": 0.62,
"fiber": 5.5,
"protein": 7.78,
"sodium": 426,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.16,
"vitaminB2": 0.127,
"vitaminB3": 1.024,
"vitaminB5": 0.346,
"vitaminB6": 0.146,
"vitaminB9": 48,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 1.54,
"vitaminK": 22.8,
"magnesium": 75,
"calcium": 47,
"phosphorus": 181,
"potassium": 312,
"iron": 2.54,
"selenium": 4.7,
"zinc": 1.44,
"manganese": 1.155,
"copper": 0.377,
"choline": 0,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 15
}
},
{
"id": 814,
"name": "PBfit Peanut Butter Powder",
"categoryId": 800,
"energy": 438,
"fat": 12.5,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 31.25,
"sugar": 18.75,
"fiber": 18.8,
"protein": 50,
"sodium": 781,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 238,
"phosphorus": 388,
"potassium": 775,
"iron": 5,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"url": "https://pbfit.com/product/pbfit-original/"
},
{
"id": 815,
"name": "PB2 Powdered Peanut Butter",
"categoryId": 800,
"energy": 462,
"fat": 11.54,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 38.46,
"sugar": 15.38,
"fiber": 7.7,
"protein": 46.15,
"sodium": 692308,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 77,
"phosphorus": 0,
"potassium": 1154,
"iron": 3.08,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"url": "https://shop.pb2foods.com/products/pb2-original-powdered-peanut-butter-peanut-butter-powder"
},
{
"id": 816,
"name": "Lentils",
"categoryId": 800,
"energy": 352,
"fat": 1.06,
"saturatedFat": 0.154,
"monounsaturatedFat": 0.193,
"polyunsaturatedFat": 0.526,
"carbs": 63.35,
"sugar": 2.03,
"fiber": 10.7,
"protein": 24.63,
"sodium": 6,
"cholesterol": 0,
"vitaminA": 2,
"vitaminB1": 0.873,
"vitaminB2": 0.211,
"vitaminB3": 2.605,
"vitaminB5": 2.14,
"vitaminB6": 0.54,
"vitaminB9": 479,
"vitaminB12": 0,
"vitaminC": 4.5,
"vitaminD": 0,
"vitaminE": 0.49,
"vitaminK": 5,
"magnesium": 47,
"calcium": 35,
"phosphorus": 281,
"potassium": 677,
"iron": 6.51,
"selenium": 0.1,
"zinc": 3.27,
"manganese": 1.393,
"copper": 0.754,
"choline": 96.4,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 12
}
},
{
"id": 817,
"name": "Peanuts",
"categoryId": 800,
"energy": 567,
"fat": 49.24,
"saturatedFat": 6.279,
"monounsaturatedFat": 24.426,
"polyunsaturatedFat": 15.558,
"carbs": 16.13,
"sugar": 4.72,
"fiber": 8.5,
"protein": 25.8,
"sodium": 18,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.64,
"vitaminB2": 0.135,
"vitaminB3": 12.066,
"vitaminB5": 1.767,
"vitaminB6": 0.348,
"vitaminB9": 240,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 8.33,
"vitaminK": 0,
"magnesium": 168,
"calcium": 92,
"phosphorus": 376,
"potassium": 705,
"iron": 4.58,
"selenium": 7.2,
"zinc": 3.27,
"manganese": 1.934,
"copper": 1.144,
"choline": 52.5,
"volume": {
"portionId": "cups",
"weightInGrams": 146
}
},
{
"id": 818,
"name": "Tofu",
"categoryId": 800,
"energy": 76,
"fat": 4.78,
"saturatedFat": 0.691,
"monounsaturatedFat": 1.056,
"polyunsaturatedFat": 2.699,
"carbs": 1.87,
"sugar": 0.62,
"fiber": 0.3,
"protein": 8.08,
"sodium": 7,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.081,
"vitaminB2": 0.052,
"vitaminB3": 0.195,
"vitaminB5": 0.068,
"vitaminB6": 0.047,
"vitaminB9": 15,
"vitaminB12": 0,
"vitaminC": 0.1,
"vitaminD": 0,
"vitaminE": 0.01,
"vitaminK": 2.4,
"magnesium": 30,
"calcium": 350,
"phosphorus": 97,
"potassium": 121,
"iron": 5.36,
"selenium": 8.9,
"zinc": 0.8,
"manganese": 0.605,
"copper": 0.193,
"choline": 28.8,
"volume": {
"portionId": "cups",
"weightInGrams": 124
}
}
]
================================================
FILE: src/foods/builtIn/nutAndSeedProducts.json
================================================
[
{
"id": 1001,
"name": "Sunflower Seeds",
"categoryId": 1000,
"energy": 584,
"fat": 51.46,
"saturatedFat": 4.455,
"monounsaturatedFat": 18.528,
"polyunsaturatedFat": 23.137,
"carbs": 20,
"sugar": 2.62,
"fiber": 8.6,
"protein": 20.78,
"sodium": 9,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 1.48,
"vitaminB2": 0.355,
"vitaminB3": 8.335,
"vitaminB5": 1.13,
"vitaminB6": 1.345,
"vitaminB9": 227,
"vitaminB12": 0,
"vitaminC": 1.4,
"vitaminD": 0,
"vitaminE": 35.17,
"vitaminK": 0,
"magnesium": 325,
"calcium": 78,
"phosphorus": 660,
"potassium": 645,
"iron": 5.25,
"selenium": 53,
"zinc": 5,
"manganese": 1.95,
"copper": 1.8,
"choline": 55.1,
"volume": {
"portionId": "cups",
"weightInGrams": 140
}
},
{
"id": 1002,
"name": "Pumpkin Seeds",
"categoryId": 1000,
"energy": 559,
"fat": 49.05,
"saturatedFat": 8.659,
"monounsaturatedFat": 16.242,
"polyunsaturatedFat": 20.976,
"carbs": 10.71,
"sugar": 1.4,
"fiber": 6,
"protein": 30.23,
"sodium": 7,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.273,
"vitaminB2": 0.153,
"vitaminB3": 4.987,
"vitaminB5": 0.75,
"vitaminB6": 0.143,
"vitaminB9": 58,
"vitaminB12": 0,
"vitaminC": 1.9,
"vitaminD": 0,
"vitaminE": 2.18,
"vitaminK": 7.3,
"magnesium": 592,
"calcium": 46,
"phosphorus": 1233,
"potassium": 809,
"iron": 8.82,
"selenium": 9.4,
"zinc": 7.81,
"manganese": 4.543,
"copper": 1.343,
"choline": 63,
"volume": {
"portionId": "cups",
"weightInGrams": 129
}
},
{
"id": 1003,
"name": "Chia Seeds",
"categoryId": 1000,
"energy": 486,
"fat": 30.74,
"saturatedFat": 3.33,
"monounsaturatedFat": 2.309,
"polyunsaturatedFat": 23.665,
"carbs": 42.12,
"sugar": 0,
"fiber": 34.4,
"protein": 16.54,
"sodium": 16,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.62,
"vitaminB2": 0.17,
"vitaminB3": 8.83,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 49,
"vitaminB12": 0,
"vitaminC": 1.6,
"vitaminD": 0,
"vitaminE": 0.5,
"vitaminK": 0,
"magnesium": 335,
"calcium": 631,
"phosphorus": 860,
"potassium": 407,
"iron": 7.72,
"selenium": 55.2,
"zinc": 4.58,
"manganese": 2.723,
"copper": 0.924,
"choline": 0
},
{
"id": 1004,
"name": "Sesame Seeds",
"categoryId": 1000,
"energy": 573,
"fat": 49.67,
"saturatedFat": 6.957,
"monounsaturatedFat": 18.759,
"polyunsaturatedFat": 21.773,
"carbs": 23.45,
"sugar": 0.3,
"fiber": 11.8,
"protein": 17.73,
"sodium": 11,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.791,
"vitaminB2": 0.247,
"vitaminB3": 4.515,
"vitaminB5": 0.05,
"vitaminB6": 0.79,
"vitaminB9": 97,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.25,
"vitaminK": 0,
"magnesium": 351,
"calcium": 975,
"phosphorus": 629,
"potassium": 468,
"iron": 14.55,
"selenium": 34.4,
"zinc": 7.75,
"manganese": 2.46,
"copper": 4.082,
"choline": 25.6,
"volume": {
"portionId": "cups",
"weightInGrams": 144
}
},
{
"id": 1005,
"name": "Coconut Flakes",
"categoryId": 1000,
"energy": 456,
"fat": 27.99,
"saturatedFat": 26.396,
"monounsaturatedFat": 1.377,
"polyunsaturatedFat": 0.222,
"carbs": 51.85,
"sugar": 36.75,
"fiber": 9.9,
"protein": 3.13,
"sodium": 285,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.015,
"vitaminB2": 0.015,
"vitaminB3": 0.697,
"vitaminB5": 0.14,
"vitaminB6": 0.03,
"vitaminB9": 3,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 51,
"calcium": 11,
"phosphorus": 100,
"potassium": 361,
"iron": 1.51,
"selenium": 16.1,
"zinc": 0.71,
"manganese": 0.959,
"copper": 0.295,
"choline": 19.3,
"volume": {
"portionId": "cups",
"weightInGrams": 85
}
},
{
"id": 1006,
"name": "Almond Butter",
"categoryId": 1000,
"energy": 614,
"fat": 55.5,
"saturatedFat": 4.152,
"monounsaturatedFat": 32.445,
"polyunsaturatedFat": 13.613,
"carbs": 18.82,
"sugar": 4.43,
"fiber": 10.3,
"protein": 20.96,
"sodium": 7,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.041,
"vitaminB2": 0.939,
"vitaminB3": 3.155,
"vitaminB5": 0.318,
"vitaminB6": 0.103,
"vitaminB9": 53,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 24.21,
"vitaminK": 0,
"magnesium": 279,
"calcium": 347,
"phosphorus": 508,
"potassium": 748,
"iron": 3.49,
"selenium": 2.4,
"zinc": 3.29,
"manganese": 2.131,
"copper": 0.934,
"choline": 52.1,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 16
}
},
{
"id": 1007,
"name": "Cashews",
"categoryId": 1000,
"energy": 553,
"fat": 43.85,
"saturatedFat": 7.783,
"monounsaturatedFat": 23.797,
"polyunsaturatedFat": 7.845,
"carbs": 30.19,
"sugar": 5.91,
"fiber": 3.3,
"protein": 18.22,
"sodium": 12,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.423,
"vitaminB2": 0.058,
"vitaminB3": 1.062,
"vitaminB5": 0.864,
"vitaminB6": 0.417,
"vitaminB9": 25,
"vitaminB12": 0,
"vitaminC": 0.5,
"vitaminD": 0,
"vitaminE": 0.9,
"vitaminK": 34.1,
"magnesium": 292,
"calcium": 37,
"phosphorus": 593,
"potassium": 660,
"iron": 6.68,
"selenium": 19.9,
"zinc": 5.78,
"manganese": 1.655,
"copper": 2.195,
"choline": 0
},
{
"id": 1008,
"name": "Pine Nuts",
"categoryId": 1000,
"energy": 673,
"fat": 68.37,
"saturatedFat": 4.899,
"monounsaturatedFat": 18.764,
"polyunsaturatedFat": 34.071,
"carbs": 13.08,
"sugar": 3.59,
"fiber": 3.7,
"protein": 13.69,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.364,
"vitaminB2": 0.227,
"vitaminB3": 4.387,
"vitaminB5": 0.313,
"vitaminB6": 0.094,
"vitaminB9": 34,
"vitaminB12": 0,
"vitaminC": 0.8,
"vitaminD": 0,
"vitaminE": 9.33,
"vitaminK": 53.9,
"magnesium": 251,
"calcium": 16,
"phosphorus": 575,
"potassium": 597,
"iron": 5.53,
"selenium": 0.7,
"zinc": 6.45,
"manganese": 8.802,
"copper": 1.324,
"choline": 55.8,
"volume": {
"portionId": "cups",
"weightInGrams": 135
}
},
{
"id": 1009,
"name": "Flaxseed",
"categoryId": 1000,
"energy": 534,
"fat": 42.16,
"saturatedFat": 3.663,
"monounsaturatedFat": 7.527,
"polyunsaturatedFat": 28.73,
"carbs": 28.88,
"sugar": 1.55,
"fiber": 27.3,
"protein": 18.29,
"sodium": 30,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 1.644,
"vitaminB2": 0.161,
"vitaminB3": 3.08,
"vitaminB5": 0.985,
"vitaminB6": 0.473,
"vitaminB9": 87,
"vitaminB12": 0,
"vitaminC": 0.6,
"vitaminD": 0,
"vitaminE": 0.31,
"vitaminK": 4.3,
"magnesium": 392,
"calcium": 255,
"phosphorus": 642,
"potassium": 813,
"iron": 5.73,
"selenium": 25.4,
"zinc": 4.34,
"manganese": 2.482,
"copper": 1.22,
"choline": 78.7,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 2.5
}
},
{
"id": 1010,
"name": "Almonds",
"categoryId": 1000,
"energy": 579,
"fat": 49.93,
"saturatedFat": 3.802,
"monounsaturatedFat": 31.551,
"polyunsaturatedFat": 12.329,
"carbs": 21.55,
"sugar": 4.35,
"fiber": 12.5,
"protein": 21.15,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.205,
"vitaminB2": 1.138,
"vitaminB3": 3.618,
"vitaminB5": 0.471,
"vitaminB6": 0.137,
"vitaminB9": 44,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 25.63,
"vitaminK": 0,
"magnesium": 270,
"calcium": 269,
"phosphorus": 481,
"potassium": 733,
"iron": 3.71,
"selenium": 4.1,
"zinc": 3.12,
"manganese": 2.179,
"copper": 1.031,
"choline": 52.1,
"volume": {
"portionId": "cups",
"weightInGrams": 143
}
},
{
"id": 1011,
"name": "Hazelnut",
"categoryId": 1000,
"energy": 628,
"fat": 60.75,
"saturatedFat": 4.464,
"monounsaturatedFat": 45.652,
"polyunsaturatedFat": 7.92,
"carbs": 16.7,
"sugar": 4.34,
"fiber": 9.7,
"protein": 14.95,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.643,
"vitaminB2": 0.113,
"vitaminB3": 1.8,
"vitaminB5": 0.918,
"vitaminB6": 0.563,
"vitaminB9": 113,
"vitaminB12": 0,
"vitaminC": 6.3,
"vitaminD": 0,
"vitaminE": 15.03,
"vitaminK": 14.2,
"magnesium": 163,
"calcium": 114,
"phosphorus": 290,
"potassium": 680,
"iron": 4.7,
"selenium": 2.4,
"zinc": 2.45,
"manganese": 6.175,
"copper": 1.725,
"choline": 45.6,
"volume": {
"portionId": "cups",
"weightInGrams": 115
}
},
{
"id": 1012,
"name": "Macadamia",
"categoryId": 1000,
"energy": 718,
"fat": 75.77,
"saturatedFat": 12.061,
"monounsaturatedFat": 58.877,
"polyunsaturatedFat": 1.502,
"carbs": 13.82,
"sugar": 4.57,
"fiber": 8.6,
"protein": 7.91,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 1.195,
"vitaminB2": 0.162,
"vitaminB3": 2.473,
"vitaminB5": 0.758,
"vitaminB6": 0.275,
"vitaminB9": 11,
"vitaminB12": 0,
"vitaminC": 1.2,
"vitaminD": 0,
"vitaminE": 0.54,
"vitaminK": 0,
"magnesium": 130,
"calcium": 85,
"phosphorus": 188,
"potassium": 368,
"iron": 3.69,
"selenium": 3.6,
"zinc": 1.3,
"manganese": 4.131,
"copper": 0.756,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 134
}
},
{
"id": 1013,
"name": "Pistachios",
"categoryId": 1000,
"energy": 560,
"fat": 45.32,
"saturatedFat": 5.907,
"monounsaturatedFat": 23.257,
"polyunsaturatedFat": 14.38,
"carbs": 27.17,
"sugar": 7.66,
"fiber": 10.6,
"protein": 20.16,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 26,
"vitaminB1": 0.87,
"vitaminB2": 0.16,
"vitaminB3": 1.3,
"vitaminB5": 0.52,
"vitaminB6": 1.7,
"vitaminB9": 51,
"vitaminB12": 0,
"vitaminC": 5.6,
"vitaminD": 0,
"vitaminE": 2.86,
"vitaminK": 0,
"magnesium": 121,
"calcium": 105,
"phosphorus": 490,
"potassium": 1025,
"iron": 3.92,
"selenium": 7,
"zinc": 2.2,
"manganese": 1.2,
"copper": 1.3,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 123
}
},
{
"id": 1014,
"name": "Pecans",
"categoryId": 1000,
"energy": 691,
"fat": 71.97,
"saturatedFat": 6.18,
"monounsaturatedFat": 40.801,
"polyunsaturatedFat": 21.614,
"carbs": 13.86,
"sugar": 3.97,
"fiber": 9.6,
"protein": 9.17,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 0.66,
"vitaminB2": 0.13,
"vitaminB3": 1.167,
"vitaminB5": 0.863,
"vitaminB6": 0.21,
"vitaminB9": 22,
"vitaminB12": 0,
"vitaminC": 1.1,
"vitaminD": 0,
"vitaminE": 1.4,
"vitaminK": 3.5,
"magnesium": 121,
"calcium": 70,
"phosphorus": 277,
"potassium": 410,
"iron": 2.53,
"selenium": 3.8,
"zinc": 4.53,
"manganese": 4.5,
"copper": 1.2,
"choline": 40.5,
"volume": {
"portionId": "cups",
"weightInGrams": 109
}
},
{
"id": 1015,
"name": "Walnuts",
"categoryId": 1000,
"energy": 654,
"fat": 65.21,
"saturatedFat": 6.126,
"monounsaturatedFat": 8.933,
"polyunsaturatedFat": 47.174,
"carbs": 13.71,
"sugar": 2.61,
"fiber": 6.7,
"protein": 15.23,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.341,
"vitaminB2": 0.15,
"vitaminB3": 1.125,
"vitaminB5": 0.57,
"vitaminB6": 0.537,
"vitaminB9": 98,
"vitaminB12": 0,
"vitaminC": 1.3,
"vitaminD": 0,
"vitaminE": 0.7,
"vitaminK": 2.7,
"magnesium": 158,
"calcium": 98,
"phosphorus": 346,
"potassium": 441,
"iron": 2.91,
"selenium": 4.9,
"zinc": 3.09,
"manganese": 3.414,
"copper": 1.586,
"choline": 39.2,
"volume": {
"portionId": "cups",
"weightInGrams": 80
}
},
{
"id": 1016,
"name": "Sunflower Seeds",
"categoryId": 1000,
"energy": 584,
"fat": 51.46,
"saturatedFat": 4.455,
"monounsaturatedFat": 18.528,
"polyunsaturatedFat": 23.137,
"carbs": 20,
"sugar": 2.62,
"fiber": 8.6,
"protein": 20.78,
"sodium": 9,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 1.48,
"vitaminB2": 0.355,
"vitaminB3": 8.335,
"vitaminB5": 1.13,
"vitaminB6": 1.345,
"vitaminB9": 227,
"vitaminB12": 0,
"vitaminC": 1.4,
"vitaminD": 0,
"vitaminE": 35.17,
"vitaminK": 0,
"magnesium": 325,
"calcium": 78,
"phosphorus": 660,
"potassium": 645,
"iron": 5.25,
"selenium": 53,
"zinc": 5,
"manganese": 1.95,
"copper": 1.8,
"choline": 55.1,
"volume": {
"portionId": "cups",
"weightInGrams": 140
}
},
{
"id": 1017,
"name": "Pumpkin Seeds",
"categoryId": 1000,
"energy": 559,
"fat": 49.05,
"saturatedFat": 8.659,
"monounsaturatedFat": 16.242,
"polyunsaturatedFat": 20.976,
"carbs": 10.71,
"sugar": 1.4,
"fiber": 6,
"protein": 30.23,
"sodium": 7,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.273,
"vitaminB2": 0.153,
"vitaminB3": 4.987,
"vitaminB5": 0.75,
"vitaminB6": 0.143,
"vitaminB9": 58,
"vitaminB12": 0,
"vitaminC": 1.9,
"vitaminD": 0,
"vitaminE": 2.18,
"vitaminK": 7.3,
"magnesium": 592,
"calcium": 46,
"phosphorus": 1233,
"potassium": 809,
"iron": 8.82,
"selenium": 9.4,
"zinc": 7.81,
"manganese": 4.543,
"copper": 1.343,
"choline": 63,
"volume": {
"portionId": "cups",
"weightInGrams": 129
}
},
{
"id": 1018,
"name": "Chia Seeds",
"categoryId": 1000,
"energy": 486,
"fat": 30.74,
"saturatedFat": 3.33,
"monounsaturatedFat": 2.309,
"polyunsaturatedFat": 23.665,
"carbs": 42.12,
"sugar": 0,
"fiber": 34.4,
"protein": 16.54,
"sodium": 16,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.62,
"vitaminB2": 0.17,
"vitaminB3": 8.83,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 49,
"vitaminB12": 0,
"vitaminC": 1.6,
"vitaminD": 0,
"vitaminE": 0.5,
"vitaminK": 0,
"magnesium": 335,
"calcium": 631,
"phosphorus": 860,
"potassium": 407,
"iron": 7.72,
"selenium": 55.2,
"zinc": 4.58,
"manganese": 2.723,
"copper": 0.924,
"choline": 0
},
{
"id": 1019,
"name": "Coconut Meat",
"categoryId": 1000,
"energy": 354,
"fat": 33.49,
"saturatedFat": 29.698,
"monounsaturatedFat": 1.425,
"polyunsaturatedFat": 0.366,
"carbs": 15.23,
"sugar": 6.23,
"fiber": 9,
"protein": 3.33,
"sodium": 20,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.066,
"vitaminB2": 0.02,
"vitaminB3": 0.54,
"vitaminB5": 0.3,
"vitaminB6": 0.054,
"vitaminB9": 26,
"vitaminB12": 0,
"vitaminC": 3.3,
"vitaminD": 0,
"vitaminE": 0.24,
"vitaminK": 0.2,
"magnesium": 32,
"calcium": 14,
"phosphorus": 113,
"potassium": 356,
"iron": 2.43,
"selenium": 10.1,
"zinc": 1.1,
"manganese": 1.5,
"copper": 0.435,
"choline": 12.1,
"volume": {
"portionId": "cups",
"weightInGrams": 80
}
},
{
"id": 1020,
"name": "Tahini",
"categoryId": 1000,
"energy": 595,
"fat": 53.76,
"saturatedFat": 7.529,
"monounsaturatedFat": 20.302,
"polyunsaturatedFat": 23.564,
"carbs": 21.19,
"sugar": 0.49,
"fiber": 9.3,
"protein": 17,
"sodium": 115,
"cholesterol": 0,
"vitaminA": 3,
"vitaminB1": 1.22,
"vitaminB2": 0.473,
"vitaminB3": 5.45,
"vitaminB5": 0.693,
"vitaminB6": 0.149,
"vitaminB9": 98,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.25,
"vitaminK": 0,
"magnesium": 95,
"calcium": 426,
"phosphorus": 732,
"potassium": 414,
"iron": 8.95,
"selenium": 34.4,
"zinc": 4.62,
"manganese": 1.456,
"copper": 1.61,
"choline": 25.8,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 15
}
},
{
"id": 1021,
"name": "Sunflower Butter",
"categoryId": 1000,
"energy": 617,
"fat": 55.2,
"saturatedFat": 4.678,
"monounsaturatedFat": 39.025,
"polyunsaturatedFat": 9.805,
"carbs": 23.32,
"sugar": 10.54,
"fiber": 5.7,
"protein": 17.28,
"sodium": 3,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.053,
"vitaminB2": 0.163,
"vitaminB3": 6.747,
"vitaminB5": 1.167,
"vitaminB6": 0.55,
"vitaminB9": 237,
"vitaminB12": 0,
"vitaminC": 2.7,
"vitaminD": 0,
"vitaminE": 22.89,
"vitaminK": 0,
"magnesium": 311,
"calcium": 64,
"phosphorus": 666,
"potassium": 576,
"iron": 4.12,
"selenium": 104.4,
"zinc": 4.89,
"manganese": 2.073,
"copper": 1.597,
"choline": 0,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 16
}
}
]
================================================
FILE: src/foods/builtIn/pork.json
================================================
[
{
"id": 301,
"name": "84% Lean Ground Pork",
"categoryId": 300,
"energy": 218,
"fat": 16,
"saturatedFat": 4.93,
"monounsaturatedFat": 6.68,
"polyunsaturatedFat": 2.05,
"carbs": 0.44,
"sugar": 0,
"fiber": 0,
"protein": 17.99,
"sodium": 68,
"cholesterol": 68,
"vitaminA": 0,
"vitaminB1": 0.332,
"vitaminB2": 0.338,
"vitaminB3": 6.416,
"vitaminB5": 0.639,
"vitaminB6": 0.551,
"vitaminB9": 2,
"vitaminB12": 0.73,
"vitaminC": 0,
"vitaminD": 0.4,
"vitaminE": 0.45,
"vitaminK": 0,
"magnesium": 16,
"calcium": 15,
"phosphorus": 161,
"potassium": 244,
"iron": 0.88,
"selenium": 30.2,
"zinc": 1.91,
"manganese": 0.01,
"copper": 0.032,
"choline": 61.5
},
{
"id": 302,
"name": "96% Lean Ground Pork",
"categoryId": 300,
"energy": 121,
"fat": 4,
"saturatedFat": 1.42,
"monounsaturatedFat": 1.89,
"polyunsaturatedFat": 0.66,
"carbs": 0.21,
"sugar": 0,
"fiber": 0,
"protein": 21.1,
"sodium": 67,
"cholesterol": 59,
"vitaminA": 0,
"vitaminB1": 0.414,
"vitaminB2": 0.368,
"vitaminB3": 7.914,
"vitaminB5": 0.646,
"vitaminB6": 0.668,
"vitaminB9": 2,
"vitaminB12": 0.64,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.29,
"vitaminK": 0,
"magnesium": 19,
"calcium": 15,
"phosphorus": 190,
"potassium": 310,
"iron": 0.86,
"selenium": 34.8,
"zinc": 1.93,
"manganese": 0.01,
"copper": 0.033,
"choline": 71.7
},
{
"id": 303,
"name": "Pork Tenderloin (fat trimmed)",
"categoryId": 300,
"energy": 109,
"fat": 2.17,
"saturatedFat": 0.698,
"monounsaturatedFat": 0.792,
"polyunsaturatedFat": 0.367,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 20.95,
"sodium": 53,
"cholesterol": 65,
"vitaminA": 0,
"vitaminB1": 0.998,
"vitaminB2": 0.342,
"vitaminB3": 6.684,
"vitaminB5": 0.846,
"vitaminB6": 0.777,
"vitaminB9": 0,
"vitaminB12": 0.51,
"vitaminC": 0,
"vitaminD": 0.2,
"vitaminE": 0.22,
"vitaminK": 0,
"magnesium": 27,
"calcium": 5,
"phosphorus": 247,
"potassium": 399,
"iron": 0.98,
"selenium": 30.8,
"zinc": 1.89,
"manganese": 0.015,
"copper": 0.09,
"choline": 80.8
},
{
"id": 304,
"name": "Canadian Bacon",
"categoryId": 300,
"energy": 110,
"fat": 2.62,
"saturatedFat": 0.9,
"monounsaturatedFat": 1.09,
"polyunsaturatedFat": 0.467,
"carbs": 1.34,
"sugar": 0.9,
"fiber": 0,
"protein": 20.31,
"sodium": 751,
"cholesterol": 48,
"vitaminA": 0,
"vitaminB1": 0.511,
"vitaminB2": 0.141,
"vitaminB3": 7.227,
"vitaminB5": 0.61,
"vitaminB6": 0.241,
"vitaminB9": 4,
"vitaminB12": 0.37,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.22,
"vitaminK": 0,
"magnesium": 20,
"calcium": 6,
"phosphorus": 240,
"potassium": 683,
"iron": 0.44,
"selenium": 37.1,
"zinc": 1.23,
"manganese": 0.015,
"copper": 0.053,
"choline": 76.1
},
{
"id": 305,
"name": "Sliced Ham",
"categoryId": 300,
"energy": 107,
"fat": 4.04,
"saturatedFat": 1.227,
"monounsaturatedFat": 1.618,
"polyunsaturatedFat": 0.626,
"carbs": 0.7,
"sugar": 0,
"fiber": 0,
"protein": 16.85,
"sodium": 945,
"cholesterol": 41,
"vitaminA": 0,
"vitaminB1": 0.336,
"vitaminB2": 0.266,
"vitaminB3": 5.697,
"vitaminB5": 0.697,
"vitaminB6": 0.394,
"vitaminB9": 0,
"vitaminB12": 0.36,
"vitaminC": 0,
"vitaminD": 0.6,
"vitaminE": 0.29,
"vitaminK": 0,
"magnesium": 19,
"calcium": 5,
"phosphorus": 252,
"potassium": 463,
"iron": 0.59,
"selenium": 31.6,
"zinc": 1.51,
"manganese": 0.014,
"copper": 0.05,
"choline": 62.4
},
{
"id": 306,
"name": "Prosciutto",
"categoryId": 300,
"energy": 195,
"fat": 8.32,
"saturatedFat": 2.78,
"monounsaturatedFat": 3.821,
"polyunsaturatedFat": 0.97,
"carbs": 0.3,
"sugar": 0,
"fiber": 0,
"protein": 27.8,
"sodium": 2695,
"cholesterol": 70,
"vitaminA": 0,
"vitaminB1": 0.567,
"vitaminB2": 0.242,
"vitaminB3": 3.881,
"vitaminB5": 0,
"vitaminB6": 0.42,
"vitaminB9": 5,
"vitaminB12": 0.88,
"vitaminC": 0,
"vitaminD": 0.9,
"vitaminE": 0.28,
"vitaminK": 0,
"magnesium": 25,
"calcium": 10,
"phosphorus": 318,
"potassium": 510,
"iron": 1.11,
"selenium": 25.8,
"zinc": 2.81,
"manganese": 0,
"copper": 0.108,
"choline": 105.5
}
]
================================================
FILE: src/foods/builtIn/poultry.json
================================================
[
{
"id": 101,
"name": "Skinless Chicken Breast",
"categoryId": 100,
"energy": 108,
"fat": 3,
"saturatedFat": 0.545,
"monounsaturatedFat": 0.673,
"polyunsaturatedFat": 0.384,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 20.32,
"sodium": 173,
"cholesterol": 64,
"vitaminA": 11,
"vitaminB1": 0.068,
"vitaminB2": 0.127,
"vitaminB3": 7.583,
"vitaminB5": 1.23,
"vitaminB6": 0.761,
"vitaminB9": 8,
"vitaminB12": 0.19,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.19,
"vitaminK": 0,
"magnesium": 25,
"calcium": 5,
"phosphorus": 198,
"potassium": 332,
"iron": 0.34,
"selenium": 26.4,
"zinc": 0.63,
"manganese": 0.011,
"copper": 0.029,
"choline": 74.2
},
{
"id": 102,
"name": "Skinless Turkey Breast",
"categoryId": 100,
"energy": 111,
"fat": 2.53,
"saturatedFat": 0.6,
"monounsaturatedFat": 3.71,
"polyunsaturatedFat": 2.903,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 21.99,
"sodium": 124,
"cholesterol": 60,
"vitaminA": 5,
"vitaminB1": 0.049,
"vitaminB2": 0.155,
"vitaminB3": 10,
"vitaminB5": 0.95,
"vitaminB6": 0.84,
"vitaminB9": 7,
"vitaminB12": 0.33,
"vitaminC": 0,
"vitaminD": 0.2,
"vitaminE": 0.1,
"vitaminK": 0,
"magnesium": 25,
"calcium": 8,
"phosphorus": 181,
"potassium": 237,
"iron": 0.41,
"selenium": 22.3,
"zinc": 1.1,
"manganese": 0.005,
"copper": 0.043,
"choline": 64.7
},
{
"id": 103,
"name": "Skinless Chicken Thigh",
"categoryId": 100,
"energy": 110,
"fat": 3.69,
"saturatedFat": 0.899,
"monounsaturatedFat": 1.222,
"polyunsaturatedFat": 0.767,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 19.11,
"sodium": 156,
"cholesterol": 87,
"vitaminA": 6,
"vitaminB1": 0.087,
"vitaminB2": 0.23,
"vitaminB3": 5.3,
"vitaminB5": 1.25,
"vitaminB6": 0.433,
"vitaminB9": 3,
"vitaminB12": 0.56,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.26,
"vitaminK": 0,
"magnesium": 21,
"calcium": 8,
"phosphorus": 175,
"potassium": 234,
"iron": 0.6,
"selenium": 20.9,
"zinc": 1.53,
"manganese": 0.009,
"copper": 0.053,
"choline": 75.1
},
{
"id": 104,
"name": "99% Lean Ground Turkey",
"categoryId": 100,
"energy": 107,
"fat": 1.34,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 23.21,
"sodium": 62,
"cholesterol": 49,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 27,
"phosphorus": 0,
"potassium": 339,
"iron": 0.36,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
},
{
"id": 105,
"name": "Skinless Turkey Thigh",
"categoryId": 100,
"energy": 116,
"fat": 3.69,
"saturatedFat": 0.782,
"monounsaturatedFat": 0.749,
"polyunsaturatedFat": 0.722,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 20.6,
"sodium": 75,
"cholesterol": 78,
"vitaminA": 19,
"vitaminB1": 0.059,
"vitaminB2": 0.307,
"vitaminB3": 6.183,
"vitaminB5": 1.3,
"vitaminB6": 0.482,
"vitaminB9": 7,
"vitaminB12": 2.17,
"vitaminC": 0,
"vitaminD": 0.5,
"vitaminE": 0.18,
"vitaminK": 0,
"magnesium": 22,
"calcium": 4,
"phosphorus": 177,
"potassium": 269,
"iron": 1.42,
"selenium": 21.5,
"zinc": 2.95,
"manganese": 0.006,
"copper": 0.083,
"choline": 75.9
},
{
"id": 106,
"name": "93% Lean Ground Turkey",
"categoryId": 100,
"energy": 150,
"fat": 8.34,
"saturatedFat": 2.17,
"monounsaturatedFat": 2.843,
"polyunsaturatedFat": 2.537,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 18.73,
"sodium": 69,
"cholesterol": 74,
"vitaminA": 22,
"vitaminB1": 0.067,
"vitaminB2": 0.185,
"vitaminB3": 5.417,
"vitaminB5": 1,
"vitaminB6": 0.35,
"vitaminB9": 7,
"vitaminB12": 1.2,
"vitaminC": 0,
"vitaminD": 0.4,
"vitaminE": 0.11,
"vitaminK": 0,
"magnesium": 21,
"calcium": 21,
"phosphorus": 193,
"potassium": 213,
"iron": 1.17,
"selenium": 19,
"zinc": 2.53,
"manganese": 0.008,
"copper": 0.107,
"choline": 53
},
{
"id": 107,
"name": "Sliced Chicken Breast",
"categoryId": 100,
"energy": 98,
"fat": 1.86,
"saturatedFat": 0.564,
"monounsaturatedFat": 0.74,
"polyunsaturatedFat": 0.452,
"carbs": 2.92,
"sugar": 0.75,
"fiber": 0,
"protein": 17.4,
"sodium": 1032,
"cholesterol": 51,
"vitaminA": 2,
"vitaminB1": 0.048,
"vitaminB2": 0.071,
"vitaminB3": 9.055,
"vitaminB5": 0.976,
"vitaminB6": 0.445,
"vitaminB9": 7,
"vitaminB12": 0.14,
"vitaminC": 0,
"vitaminD": 0.1,
"vitaminE": 0.32,
"vitaminK": 0,
"magnesium": 26,
"calcium": 11,
"phosphorus": 257,
"potassium": 360,
"iron": 0.39,
"selenium": 13.2,
"zinc": 0.51,
"manganese": 0.018,
"copper": 0.02,
"choline": 44.2
},
{
"id": 108,
"name": "85% Lean Ground Turkey",
"categoryId": 100,
"energy": 180,
"fat": 12.54,
"saturatedFat": 3.414,
"monounsaturatedFat": 4.551,
"polyunsaturatedFat": 3.485,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 16.9,
"sodium": 54,
"cholesterol": 78,
"vitaminA": 30,
"vitaminB1": 0.067,
"vitaminB2": 0.177,
"vitaminB3": 5.075,
"vitaminB5": 1.1,
"vitaminB6": 0.485,
"vitaminB9": 6,
"vitaminB12": 1.3,
"vitaminC": 0,
"vitaminD": 0.4,
"vitaminE": 0.08,
"vitaminK": 0,
"magnesium": 19,
"calcium": 33,
"phosphorus": 179,
"potassium": 202,
"iron": 1.32,
"selenium": 24.6,
"zinc": 2.75,
"manganese": 0.009,
"copper": 0.123,
"choline": 51.6
},
{
"id": 109,
"name": "Andouille Chicken Sausage",
"categoryId": 100,
"energy": 161,
"fat": 10.71,
"saturatedFat": 2.68,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 3.57,
"sugar": 1.79,
"fiber": 0,
"protein": 14.29,
"sodium": 714,
"cholesterol": 71,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 1.29,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
},
{
"id": 110,
"name": "Sliced Turkey Breast",
"categoryId": 100,
"energy": 106,
"fat": 3.77,
"saturatedFat": 0.906,
"monounsaturatedFat": 1.145,
"polyunsaturatedFat": 1.024,
"carbs": 2.2,
"sugar": 0.91,
"fiber": 0,
"protein": 14.81,
"sodium": 898,
"cholesterol": 49,
"vitaminA": 0,
"vitaminB1": 0.038,
"vitaminB2": 0.145,
"vitaminB3": 7.15,
"vitaminB5": 0.32,
"vitaminB6": 0.41,
"vitaminB9": 4,
"vitaminB12": 0.37,
"vitaminC": 0,
"vitaminD": 0.2,
"vitaminE": 0.13,
"vitaminK": 0,
"magnesium": 19,
"calcium": 14,
"phosphorus": 249,
"potassium": 371,
"iron": 0.42,
"selenium": 13,
"zinc": 0.94,
"manganese": 0.016,
"copper": 0.024,
"choline": 30.1
}
]
================================================
FILE: src/foods/builtIn/saucesAndSoups.json
================================================
[
{
"id": 4001,
"name": "Sriracha",
"categoryId": 4000,
"energy": 93,
"fat": 0.93,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 19.16,
"sugar": 15.11,
"fiber": 2.2,
"protein": 1.93,
"sodium": 2124,
"cholesterol": 0,
"vitaminA": 129,
"vitaminB1": 0.077,
"vitaminB2": 0.222,
"vitaminB3": 1.248,
"vitaminB5": 0.38,
"vitaminB6": 0.455,
"vitaminB9": 22,
"vitaminB12": 0,
"vitaminC": 26.9,
"vitaminD": 0,
"vitaminE": 4.8,
"vitaminK": 10.9,
"magnesium": 16,
"calcium": 18,
"phosphorus": 46,
"potassium": 321,
"iron": 1.64,
"selenium": 0.4,
"zinc": 0.24,
"manganese": 0.146,
"copper": 0.06,
"choline": 0,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 6.5
}
},
{
"id": 4002,
"name": "Salsa",
"categoryId": 4000,
"energy": 29,
"fat": 0.17,
"saturatedFat": 0.021,
"monounsaturatedFat": 0.018,
"polyunsaturatedFat": 0.078,
"carbs": 6.64,
"sugar": 4.01,
"fiber": 1.9,
"protein": 1.52,
"sodium": 711,
"cholesterol": 0,
"vitaminA": 23,
"vitaminB1": 0.033,
"vitaminB2": 0.032,
"vitaminB3": 1.091,
"vitaminB5": 0.199,
"vitaminB6": 0.172,
"vitaminB9": 4,
"vitaminB12": 0,
"vitaminC": 1.9,
"vitaminD": 0,
"vitaminE": 1.28,
"vitaminK": 4.3,
"magnesium": 15,
"calcium": 30,
"phosphorus": 33,
"potassium": 275,
"iron": 0.42,
"selenium": 0.9,
"zinc": 0.18,
"manganese": 0.112,
"copper": 0.066,
"choline": 12.8,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 36
}
},
{
"id": 4003,
"name": "Teriyaki Sauce",
"categoryId": 4000,
"energy": 89,
"fat": 0.02,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 15.58,
"sugar": 14.1,
"fiber": 0.1,
"protein": 5.93,
"sodium": 1778,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.03,
"vitaminB2": 0.07,
"vitaminB3": 1.27,
"vitaminB5": 0,
"vitaminB6": 0.1,
"vitaminB9": 8,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 61,
"calcium": 25,
"phosphorus": 154,
"potassium": 225,
"iron": 1.7,
"selenium": 0.8,
"zinc": 0.1,
"manganese": 0,
"copper": 0.1,
"choline": 19.5,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 36
}
},
{
"id": 4004,
"name": "Honey Dijon Mustard",
"categoryId": 4000,
"energy": 200,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 20,
"sugar": 20,
"fiber": 0,
"protein": 0,
"sodium": 1300,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
},
{
"id": 4005,
"name": "Coconut Aminos",
"categoryId": 4000,
"energy": 200,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 46.67,
"sugar": 40,
"fiber": 0,
"protein": 0,
"sodium": 3200,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 10,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
},
{
"id": 4006,
"name": "Barbecue Sauce",
"categoryId": 4000,
"energy": 172,
"fat": 0.63,
"saturatedFat": 0.045,
"monounsaturatedFat": 0.082,
"polyunsaturatedFat": 0.101,
"carbs": 40.77,
"sugar": 33.24,
"fiber": 0.9,
"protein": 0.82,
"sodium": 1027,
"cholesterol": 0,
"vitaminA": 11,
"vitaminB1": 0.023,
"vitaminB2": 0.056,
"vitaminB3": 0.597,
"vitaminB5": 0,
"vitaminB6": 0.075,
"vitaminB9": 2,
"vitaminB12": 0,
"vitaminC": 0.6,
"vitaminD": 0,
"vitaminE": 0.8,
"vitaminK": 1.8,
"magnesium": 13,
"calcium": 33,
"phosphorus": 20,
"potassium": 232,
"iron": 0.64,
"selenium": 1.3,
"zinc": 0.17,
"manganese": 0,
"copper": 0.072,
"choline": 7.1
},
{
"id": 4007,
"name": "Ketchup",
"categoryId": 4000,
"energy": 101,
"fat": 0.1,
"saturatedFat": 0.014,
"monounsaturatedFat": 0.015,
"polyunsaturatedFat": 0.041,
"carbs": 27.4,
"sugar": 21.27,
"fiber": 0.3,
"protein": 1.04,
"sodium": 907,
"cholesterol": 0,
"vitaminA": 26,
"vitaminB1": 0.011,
"vitaminB2": 0.166,
"vitaminB3": 1.434,
"vitaminB5": 0,
"vitaminB6": 0.158,
"vitaminB9": 9,
"vitaminB12": 0,
"vitaminC": 4.1,
"vitaminD": 0,
"vitaminE": 1.46,
"vitaminK": 3,
"magnesium": 13,
"calcium": 15,
"phosphorus": 26,
"potassium": 281,
"iron": 0.35,
"selenium": 0.7,
"zinc": 0.17,
"manganese": 0,
"copper": 0.085,
"choline": 12.5
},
{
"id": 4008,
"name": "A1 Steak Sauce",
"categoryId": 4000,
"energy": 95,
"fat": 0.23,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 22.04,
"sugar": 9.82,
"fiber": 1.5,
"protein": 1.25,
"sodium": 1647,
"cholesterol": 0,
"vitaminA": 15,
"vitaminB1": 0.034,
"vitaminB2": 0.054,
"vitaminB3": 0.913,
"vitaminB5": 0,
"vitaminB6": 0.105,
"vitaminB9": 8,
"vitaminB12": 0,
"vitaminC": 6.8,
"vitaminD": 0,
"vitaminE": 1.16,
"vitaminK": 2.2,
"magnesium": 17,
"calcium": 19,
"phosphorus": 33,
"potassium": 312,
"iron": 1.37,
"selenium": 0.8,
"zinc": 0.34,
"manganese": 0,
"copper": 0.189,
"choline": 11.5
},
{
"id": 4009,
"name": "Mustard",
"categoryId": 4000,
"energy": 61,
"fat": 3.38,
"saturatedFat": 0.252,
"monounsaturatedFat": 2.59,
"polyunsaturatedFat": 0.903,
"carbs": 5.3,
"sugar": 1.42,
"fiber": 4.3,
"protein": 4.25,
"sodium": 1100,
"cholesterol": 0,
"vitaminA": 4,
"vitaminB1": 0.189,
"vitaminB2": 0.066,
"vitaminB3": 0.561,
"vitaminB5": 0,
"vitaminB6": 0.069,
"vitaminB9": 7,
"vitaminB12": 0,
"vitaminC": 0.4,
"vitaminD": 0,
"vitaminE": 0.35,
"vitaminK": 1.5,
"magnesium": 48,
"calcium": 63,
"phosphorus": 108,
"potassium": 150,
"iron": 1.59,
"selenium": 34,
"zinc": 0.64,
"manganese": 0,
"copper": 0.074,
"choline": 22.4
},
{
"id": 4010,
"name": "Soy Sauce",
"categoryId": 4000,
"energy": 53,
"fat": 0.57,
"saturatedFat": 0.073,
"monounsaturatedFat": 0.088,
"polyunsaturatedFat": 0.263,
"carbs": 4.93,
"sugar": 0.4,
"fiber": 0.8,
"protein": 8.14,
"sodium": 5493,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.033,
"vitaminB2": 0.165,
"vitaminB3": 2.196,
"vitaminB5": 0,
"vitaminB6": 0.148,
"vitaminB9": 14,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 74,
"calcium": 33,
"phosphorus": 166,
"potassium": 435,
"iron": 1.45,
"selenium": 0.5,
"zinc": 0.87,
"manganese": 0,
"copper": 0.043,
"choline": 18.3
},
{
"id": 4011,
"name": "Worcestershire Sauce",
"categoryId": 4000,
"energy": 77,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 19.17,
"sugar": 10.03,
"fiber": 0,
"protein": 0,
"sodium": 1300,
"cholesterol": 0,
"vitaminA": 5,
"vitaminB1": 0.07,
"vitaminB2": 0.13,
"vitaminB3": 0.7,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 8,
"vitaminB12": 0,
"vitaminC": 13,
"vitaminD": 0,
"vitaminE": 0.08,
"vitaminK": 1,
"magnesium": 13,
"calcium": 107,
"phosphorus": 60,
"potassium": 800,
"iron": 5.3,
"selenium": 0.5,
"zinc": 0.19,
"manganese": 0,
"copper": 0.2,
"choline": 2.7
},
{
"id": 4012,
"name": "Hot Sauce",
"categoryId": 4000,
"energy": 12,
"fat": 0.76,
"saturatedFat": 0.106,
"monounsaturatedFat": 0.061,
"polyunsaturatedFat": 0.401,
"carbs": 0.8,
"sugar": 0.13,
"fiber": 0.6,
"protein": 1.29,
"sodium": 633,
"cholesterol": 0,
"vitaminA": 82,
"vitaminB1": 0.032,
"vitaminB2": 0.084,
"vitaminB3": 0.178,
"vitaminB5": 0,
"vitaminB6": 0.154,
"vitaminB9": 1,
"vitaminB12": 0,
"vitaminC": 4.5,
"vitaminD": 0,
"vitaminE": 0.01,
"vitaminK": 0.2,
"magnesium": 12,
"calcium": 12,
"phosphorus": 23,
"potassium": 128,
"iron": 1.16,
"selenium": 0.5,
"zinc": 0.16,
"manganese": 0,
"copper": 0.075,
"choline": 0
},
{
"id": 4013,
"name": "Fish Sauce",
"categoryId": 4000,
"energy": 35,
"fat": 0.01,
"saturatedFat": 0.003,
"monounsaturatedFat": 0.002,
"polyunsaturatedFat": 0.003,
"carbs": 3.64,
"sugar": 3.64,
"fiber": 0,
"protein": 5.06,
"sodium": 7851,
"cholesterol": 0,
"vitaminA": 4,
"vitaminB1": 0.012,
"vitaminB2": 0.057,
"vitaminB3": 2.313,
"vitaminB5": 0.118,
"vitaminB6": 0.396,
"vitaminB9": 51,
"vitaminB12": 0.48,
"vitaminC": 0.5,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 175,
"calcium": 43,
"phosphorus": 7,
"potassium": 288,
"iron": 0.78,
"selenium": 9.1,
"zinc": 0.2,
"manganese": 0.233,
"copper": 0.05,
"choline": 13.2,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 18
}
},
{
"id": 4014,
"name": "Pico de Gallo",
"categoryId": 4000,
"energy": 17,
"fat": 0.14,
"saturatedFat": 0.023,
"monounsaturatedFat": 0.02,
"polyunsaturatedFat": 0.057,
"carbs": 3.7,
"sugar": 2.13,
"fiber": 1.1,
"protein": 0.71,
"sodium": 443,
"cholesterol": 0,
"vitaminA": 25,
"vitaminB1": 0.028,
"vitaminB2": 0.02,
"vitaminB3": 0.407,
"vitaminB5": 0,
"vitaminB6": 0.091,
"vitaminB9": 12,
"vitaminB12": 0,
"vitaminC": 10.8,
"vitaminD": 0,
"vitaminE": 0.32,
"vitaminK": 6.9,
"magnesium": 9,
"calcium": 11,
"phosphorus": 19,
"potassium": 157,
"iron": 0.23,
"selenium": 0.1,
"zinc": 0.13,
"manganese": 0,
"copper": 0.047,
"choline": 4.7
},
{
"id": 4015,
"name": "Chicken Broth",
"categoryId": 4000,
"energy": 6,
"fat": 0.21,
"saturatedFat": 0.013,
"monounsaturatedFat": 0.019,
"polyunsaturatedFat": 0.009,
"carbs": 0.44,
"sugar": 0.43,
"fiber": 0,
"protein": 0.64,
"sodium": 371,
"cholesterol": 2,
"vitaminA": 0,
"vitaminB1": 0.021,
"vitaminB2": 0.059,
"vitaminB3": 0.219,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0.02,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.04,
"vitaminK": 0,
"magnesium": 1,
"calcium": 4,
"phosphorus": 4,
"potassium": 18,
"iron": 0.07,
"selenium": 0.4,
"zinc": 0.07,
"manganese": 0.015,
"copper": 0.015,
"choline": 1,
"volume": {
"portionId": "cups",
"weightInGrams": 249
}
},
{
"id": 4016,
"name": "Pizza Sauce",
"categoryId": 4000,
"energy": 54,
"fat": 1.15,
"saturatedFat": 0.46,
"monounsaturatedFat": 0.461,
"polyunsaturatedFat": 0.099,
"carbs": 8.66,
"sugar": 3.78,
"fiber": 2,
"protein": 2.18,
"sodium": 348,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.061,
"vitaminB2": 0.053,
"vitaminB3": 1.421,
"vitaminB5": 0.374,
"vitaminB6": 0.136,
"vitaminB9": 10,
"vitaminB12": 0.02,
"vitaminC": 11.3,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 21,
"calcium": 54,
"phosphorus": 50,
"potassium": 354,
"iron": 0.9,
"selenium": 0,
"zinc": 0.25,
"manganese": 0.221,
"copper": 0.137,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 63
}
},
{
"id": 4017,
"name": "Pasta Sauce",
"categoryId": 4000,
"energy": 50,
"fat": 1.61,
"saturatedFat": 0.218,
"monounsaturatedFat": 0.298,
"polyunsaturatedFat": 0.673,
"carbs": 7.43,
"sugar": 4.91,
"fiber": 1.8,
"protein": 1.39,
"sodium": 437,
"cholesterol": 2,
"vitaminA": 31,
"vitaminB1": 0.024,
"vitaminB2": 0.061,
"vitaminB3": 3.917,
"vitaminB5": 0.076,
"vitaminB6": 0.173,
"vitaminB9": 13,
"vitaminB12": 0,
"vitaminC": 2,
"vitaminD": 0,
"vitaminE": 2.4,
"vitaminK": 13.9,
"magnesium": 18,
"calcium": 26,
"phosphorus": 34,
"potassium": 320,
"iron": 0.73,
"selenium": 1.4,
"zinc": 0.2,
"manganese": 0.127,
"copper": 0.082,
"choline": 13.7,
"volume": {
"portionId": "cups",
"weightInGrams": 132
}
},
{
"id": 4018,
"name": "Chicken Stock",
"categoryId": 4000,
"energy": 36,
"fat": 1.2,
"saturatedFat": 0.321,
"monounsaturatedFat": 0.582,
"polyunsaturatedFat": 0.213,
"carbs": 3.53,
"sugar": 1.58,
"fiber": 0,
"protein": 2.52,
"sodium": 143,
"cholesterol": 3,
"vitaminA": 1,
"vitaminB1": 0.035,
"vitaminB2": 0.085,
"vitaminB3": 1.584,
"vitaminB5": 0,
"vitaminB6": 0.061,
"vitaminB9": 5,
"vitaminB12": 0,
"vitaminC": 0.2,
"vitaminD": 0,
"vitaminE": 0.03,
"vitaminK": 0.2,
"magnesium": 4,
"calcium": 3,
"phosphorus": 27,
"potassium": 105,
"iron": 0.21,
"selenium": 2.2,
"zinc": 0.14,
"manganese": 0,
"copper": 0.054,
"choline": 9.2,
"volume": {
"portionId": "cups",
"weightInGrams": 240
}
}
]
================================================
FILE: src/foods/builtIn/spicesAndHerbs.json
================================================
[
{
"id": 5001,
"name": "Salt",
"categoryId": 5000,
"energy": 0,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0,
"sodium": 38758,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 1,
"calcium": 24,
"phosphorus": 0,
"potassium": 8,
"iron": 0.33,
"selenium": 0.1,
"zinc": 0.1,
"manganese": 0.1,
"copper": 0.03,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 292
}
},
{
"id": 5002,
"name": "Cinnamon",
"categoryId": 5000,
"energy": 247,
"fat": 1.24,
"saturatedFat": 0.345,
"monounsaturatedFat": 0.246,
"polyunsaturatedFat": 0.068,
"carbs": 80.59,
"sugar": 2.17,
"fiber": 53.1,
"protein": 3.99,
"sodium": 10,
"cholesterol": 0,
"vitaminA": 15,
"vitaminB1": 0.022,
"vitaminB2": 0.041,
"vitaminB3": 1.332,
"vitaminB5": 0.358,
"vitaminB6": 0.158,
"vitaminB9": 6,
"vitaminB12": 0,
"vitaminC": 3.8,
"vitaminD": 0,
"vitaminE": 2.32,
"vitaminK": 31.2,
"magnesium": 60,
"calcium": 1002,
"phosphorus": 64,
"potassium": 431,
"iron": 8.32,
"selenium": 3.1,
"zinc": 1.83,
"manganese": 17.466,
"copper": 0.339,
"choline": 11,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 2.6
}
},
{
"id": 5003,
"name": "Vanilla Extract",
"categoryId": 5000,
"energy": 288,
"fat": 0.06,
"saturatedFat": 0.01,
"monounsaturatedFat": 0.01,
"polyunsaturatedFat": 0.004,
"carbs": 12.65,
"sugar": 12.65,
"fiber": 0,
"protein": 0.06,
"sodium": 9,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.011,
"vitaminB2": 0.095,
"vitaminB3": 0.425,
"vitaminB5": 0.035,
"vitaminB6": 0.026,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 12,
"calcium": 11,
"phosphorus": 6,
"potassium": 148,
"iron": 0.12,
"selenium": 0,
"zinc": 0.11,
"manganese": 0.23,
"copper": 0.072,
"choline": 0,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 4.2
}
},
{
"id": 5004,
"name": "Balsamic Vinegar",
"categoryId": 5000,
"energy": 88,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 17.03,
"sugar": 14.95,
"fiber": 0,
"protein": 0.49,
"sodium": 23,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 12,
"calcium": 27,
"phosphorus": 19,
"potassium": 112,
"iron": 0.72,
"selenium": 0,
"zinc": 0.08,
"manganese": 0.131,
"copper": 0.026,
"choline": 0,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 16
}
},
{
"id": 5005,
"name": "Garlic",
"categoryId": 5000,
"energy": 149,
"fat": 0.5,
"saturatedFat": 0.089,
"monounsaturatedFat": 0.011,
"polyunsaturatedFat": 0.249,
"carbs": 33.06,
"sugar": 1,
"fiber": 2.1,
"protein": 6.36,
"sodium": 17,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.2,
"vitaminB2": 0.11,
"vitaminB3": 0.7,
"vitaminB5": 0.596,
"vitaminB6": 1.235,
"vitaminB9": 3,
"vitaminB12": 0,
"vitaminC": 31.2,
"vitaminD": 0,
"vitaminE": 0.08,
"vitaminK": 1.7,
"magnesium": 25,
"calcium": 181,
"phosphorus": 153,
"potassium": 401,
"iron": 1.7,
"selenium": 14.2,
"zinc": 1.16,
"manganese": 1.672,
"copper": 0.299,
"choline": 23.2,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 2.8
}
},
{
"id": 5006,
"name": "Fresh Mint",
"categoryId": 5000,
"energy": 44,
"fat": 0.73,
"saturatedFat": 0.191,
"monounsaturatedFat": 0.025,
"polyunsaturatedFat": 0.394,
"carbs": 8.41,
"sugar": 0,
"fiber": 6.8,
"protein": 3.29,
"sodium": 30,
"cholesterol": 0,
"vitaminA": 203,
"vitaminB1": 0.078,
"vitaminB2": 0.175,
"vitaminB3": 0.948,
"vitaminB5": 0.25,
"vitaminB6": 0.158,
"vitaminB9": 105,
"vitaminB12": 0,
"vitaminC": 13.3,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 63,
"calcium": 199,
"phosphorus": 60,
"potassium": 458,
"iron": 11.87,
"selenium": 0,
"zinc": 1.09,
"manganese": 1.118,
"copper": 0.24,
"choline": 0,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 11.4
}
},
{
"id": 5007,
"name": "Fresh Basil",
"categoryId": 5000,
"energy": 23,
"fat": 0.64,
"saturatedFat": 0.041,
"monounsaturatedFat": 0.088,
"polyunsaturatedFat": 0.389,
"carbs": 2.65,
"sugar": 0.3,
"fiber": 1.6,
"protein": 3.15,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 264,
"vitaminB1": 0.034,
"vitaminB2": 0.076,
"vitaminB3": 0.902,
"vitaminB5": 0.209,
"vitaminB6": 0.155,
"vitaminB9": 68,
"vitaminB12": 0,
"vitaminC": 18,
"vitaminD": 0,
"vitaminE": 0.8,
"vitaminK": 414.8,
"magnesium": 64,
"calcium": 177,
"phosphorus": 56,
"potassium": 295,
"iron": 3.17,
"selenium": 0.3,
"zinc": 0.81,
"manganese": 1.148,
"copper": 0.385,
"choline": 11.4,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 5.3
}
},
{
"id": 5008,
"name": "Nutmeg",
"categoryId": 5000,
"energy": 525,
"fat": 36.31,
"saturatedFat": 25.94,
"monounsaturatedFat": 3.22,
"polyunsaturatedFat": 0.35,
"carbs": 49.29,
"sugar": 2.99,
"fiber": 20.8,
"protein": 5.84,
"sodium": 16,
"cholesterol": 0,
"vitaminA": 5,
"vitaminB1": 0.346,
"vitaminB2": 0.057,
"vitaminB3": 1.299,
"vitaminB5": 0,
"vitaminB6": 0.16,
"vitaminB9": 76,
"vitaminB12": 0,
"vitaminC": 3,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 183,
"calcium": 184,
"phosphorus": 213,
"potassium": 350,
"iron": 3.04,
"selenium": 1.6,
"zinc": 2.15,
"manganese": 2.9,
"copper": 1.027,
"choline": 8.8,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 7
}
},
{
"id": 5009,
"name": "Black Pepper",
"categoryId": 5000,
"energy": 251,
"fat": 3.26,
"saturatedFat": 1.392,
"monounsaturatedFat": 0.739,
"polyunsaturatedFat": 0.998,
"carbs": 63.95,
"sugar": 0.64,
"fiber": 25.3,
"protein": 10.39,
"sodium": 20,
"cholesterol": 0,
"vitaminA": 27,
"vitaminB1": 0.108,
"vitaminB2": 0.18,
"vitaminB3": 1.143,
"vitaminB5": 1.399,
"vitaminB6": 0.291,
"vitaminB9": 17,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 1.04,
"vitaminK": 163.7,
"magnesium": 171,
"calcium": 443,
"phosphorus": 158,
"potassium": 1329,
"iron": 9.71,
"selenium": 4.9,
"zinc": 1.19,
"manganese": 12.753,
"copper": 1.33,
"choline": 11.3,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 6.9
}
},
{
"id": 5010,
"name": "Salt",
"categoryId": 5000,
"energy": 0,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0,
"sodium": 38758,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 1,
"calcium": 24,
"phosphorus": 0,
"potassium": 8,
"iron": 0.33,
"selenium": 0.1,
"zinc": 0.1,
"manganese": 0.1,
"copper": 0.03,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 292
}
},
{
"id": 5011,
"name": "Paprika",
"categoryId": 5000,
"energy": 282,
"fat": 12.89,
"saturatedFat": 2.14,
"monounsaturatedFat": 1.695,
"polyunsaturatedFat": 7.766,
"carbs": 53.99,
"sugar": 10.34,
"fiber": 34.9,
"protein": 14.14,
"sodium": 68,
"cholesterol": 0,
"vitaminA": 2463,
"vitaminB1": 0.33,
"vitaminB2": 1.23,
"vitaminB3": 10.06,
"vitaminB5": 2.51,
"vitaminB6": 2.141,
"vitaminB9": 49,
"vitaminB12": 0,
"vitaminC": 0.9,
"vitaminD": 0,
"vitaminE": 29.1,
"vitaminK": 80.3,
"magnesium": 178,
"calcium": 229,
"phosphorus": 314,
"potassium": 2280,
"iron": 21.14,
"selenium": 6.3,
"zinc": 4.33,
"manganese": 1.59,
"copper": 0.713,
"choline": 51.5,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 6.8
}
},
{
"id": 5012,
"name": "Cayenne Pepper",
"categoryId": 5000,
"energy": 318,
"fat": 17.27,
"saturatedFat": 3.26,
"monounsaturatedFat": 2.75,
"polyunsaturatedFat": 8.37,
"carbs": 56.63,
"sugar": 10.34,
"fiber": 27.2,
"protein": 12.01,
"sodium": 30,
"cholesterol": 0,
"vitaminA": 2081,
"vitaminB1": 0.328,
"vitaminB2": 0.919,
"vitaminB3": 8.701,
"vitaminB5": 0,
"vitaminB6": 2.45,
"vitaminB9": 106,
"vitaminB12": 0,
"vitaminC": 76.4,
"vitaminD": 0,
"vitaminE": 29.83,
"vitaminK": 80.3,
"magnesium": 152,
"calcium": 148,
"phosphorus": 293,
"potassium": 2014,
"iron": 7.8,
"selenium": 8.8,
"zinc": 2.48,
"manganese": 2,
"copper": 0.373,
"choline": 51.5,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 5.3
}
},
{
"id": 5013,
"name": "Cumin",
"categoryId": 5000,
"energy": 375,
"fat": 22.27,
"saturatedFat": 1.535,
"monounsaturatedFat": 14.04,
"polyunsaturatedFat": 3.279,
"carbs": 44.24,
"sugar": 2.25,
"fiber": 10.5,
"protein": 17.81,
"sodium": 168,
"cholesterol": 0,
"vitaminA": 64,
"vitaminB1": 0.628,
"vitaminB2": 0.327,
"vitaminB3": 4.579,
"vitaminB5": 0,
"vitaminB6": 0.435,
"vitaminB9": 10,
"vitaminB12": 0,
"vitaminC": 7.7,
"vitaminD": 0,
"vitaminE": 3.33,
"vitaminK": 5.4,
"magnesium": 366,
"calcium": 931,
"phosphorus": 499,
"potassium": 1788,
"iron": 66.36,
"selenium": 5.2,
"zinc": 4.8,
"manganese": 3.333,
"copper": 0.867,
"choline": 24.7,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 2.1
}
},
{
"id": 5014,
"name": "Fresh Thyme",
"categoryId": 5000,
"energy": 101,
"fat": 1.68,
"saturatedFat": 0.467,
"monounsaturatedFat": 0.081,
"polyunsaturatedFat": 0.532,
"carbs": 24.45,
"sugar": 0,
"fiber": 14,
"protein": 5.56,
"sodium": 9,
"cholesterol": 0,
"vitaminA": 238,
"vitaminB1": 0.048,
"vitaminB2": 0.471,
"vitaminB3": 1.824,
"vitaminB5": 0.409,
"vitaminB6": 0.348,
"vitaminB9": 45,
"vitaminB12": 0,
"vitaminC": 160.1,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 160,
"calcium": 405,
"phosphorus": 106,
"potassium": 609,
"iron": 17.45,
"selenium": 0,
"zinc": 1.81,
"manganese": 1.719,
"copper": 0.555,
"choline": 0,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 0.8
}
},
{
"id": 5015,
"name": "Dried Thyme",
"categoryId": 5000,
"energy": 276,
"fat": 7.43,
"saturatedFat": 2.73,
"monounsaturatedFat": 0.47,
"polyunsaturatedFat": 1.19,
"carbs": 63.94,
"sugar": 1.71,
"fiber": 37,
"protein": 9.11,
"sodium": 55,
"cholesterol": 0,
"vitaminA": 190,
"vitaminB1": 0.513,
"vitaminB2": 0.399,
"vitaminB3": 4.94,
"vitaminB5": 0,
"vitaminB6": 0.55,
"vitaminB9": 274,
"vitaminB12": 0,
"vitaminC": 50,
"vitaminD": 0,
"vitaminE": 7.48,
"vitaminK": 1714.5,
"magnesium": 220,
"calcium": 1890,
"phosphorus": 201,
"potassium": 814,
"iron": 123.6,
"selenium": 4.6,
"zinc": 6.18,
"manganese": 7.867,
"copper": 0.86,
"choline": 43.6,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 1
}
},
{
"id": 5016,
"name": "Ground Ginger",
"categoryId": 5000,
"energy": 335,
"fat": 4.24,
"saturatedFat": 2.599,
"monounsaturatedFat": 0.479,
"polyunsaturatedFat": 0.929,
"carbs": 71.62,
"sugar": 3.39,
"fiber": 14.1,
"protein": 8.98,
"sodium": 27,
"cholesterol": 0,
"vitaminA": 2,
"vitaminB1": 0.046,
"vitaminB2": 0.17,
"vitaminB3": 9.62,
"vitaminB5": 0.477,
"vitaminB6": 0.626,
"vitaminB9": 13,
"vitaminB12": 0,
"vitaminC": 0.7,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0.8,
"magnesium": 214,
"calcium": 114,
"phosphorus": 168,
"potassium": 1320,
"iron": 19.8,
"selenium": 55.8,
"zinc": 3.64,
"manganese": 33.3,
"copper": 0.48,
"choline": 41.2,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 5.2
}
},
{
"id": 5017,
"name": "Fresh Rosemary",
"categoryId": 5000,
"energy": 131,
"fat": 5.86,
"saturatedFat": 2.838,
"monounsaturatedFat": 1.16,
"polyunsaturatedFat": 0.901,
"carbs": 20.7,
"sugar": 0,
"fiber": 14.1,
"protein": 3.31,
"sodium": 26,
"cholesterol": 0,
"vitaminA": 146,
"vitaminB1": 0.036,
"vitaminB2": 0.152,
"vitaminB3": 0.912,
"vitaminB5": 0.804,
"vitaminB6": 0.336,
"vitaminB9": 109,
"vitaminB12": 0,
"vitaminC": 21.8,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 91,
"calcium": 317,
"phosphorus": 66,
"potassium": 668,
"iron": 6.65,
"selenium": 0,
"zinc": 0.93,
"manganese": 0.96,
"copper": 0.301,
"choline": 0,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 1.7
}
},
{
"id": 5018,
"name": "Dried Rosemary",
"categoryId": 5000,
"energy": 331,
"fat": 15.22,
"saturatedFat": 7.371,
"monounsaturatedFat": 3.014,
"polyunsaturatedFat": 2.339,
"carbs": 64.06,
"sugar": 0,
"fiber": 42.6,
"protein": 4.88,
"sodium": 50,
"cholesterol": 0,
"vitaminA": 156,
"vitaminB1": 0.514,
"vitaminB2": 0.428,
"vitaminB3": 1,
"vitaminB5": 0,
"vitaminB6": 1.74,
"vitaminB9": 307,
"vitaminB12": 0,
"vitaminC": 61.2,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 220,
"calcium": 1280,
"phosphorus": 70,
"potassium": 955,
"iron": 29.25,
"selenium": 4.6,
"zinc": 3.23,
"manganese": 1.867,
"copper": 0.55,
"choline": 0,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 1.2
}
},
{
"id": 5019,
"name": "Dried Oregano",
"categoryId": 5000,
"energy": 265,
"fat": 4.28,
"saturatedFat": 1.551,
"monounsaturatedFat": 0.716,
"polyunsaturatedFat": 1.369,
"carbs": 68.92,
"sugar": 4.09,
"fiber": 42.5,
"protein": 9,
"sodium": 25,
"cholesterol": 0,
"vitaminA": 85,
"vitaminB1": 0.177,
"vitaminB2": 0.528,
"vitaminB3": 4.64,
"vitaminB5": 0.921,
"vitaminB6": 1.044,
"vitaminB9": 237,
"vitaminB12": 0,
"vitaminC": 2.3,
"vitaminD": 0,
"vitaminE": 18.26,
"vitaminK": 621.7,
"magnesium": 270,
"calcium": 1597,
"phosphorus": 148,
"potassium": 1260,
"iron": 36.8,
"selenium": 4.5,
"zinc": 2.69,
"manganese": 4.99,
"copper": 0.633,
"choline": 32.3,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 1
}
},
{
"id": 5020,
"name": "Ground Sage",
"categoryId": 5000,
"energy": 315,
"fat": 12.75,
"saturatedFat": 7.03,
"monounsaturatedFat": 1.87,
"polyunsaturatedFat": 1.76,
"carbs": 60.73,
"sugar": 1.71,
"fiber": 40.3,
"protein": 10.63,
"sodium": 11,
"cholesterol": 0,
"vitaminA": 295,
"vitaminB1": 0.754,
"vitaminB2": 0.336,
"vitaminB3": 5.72,
"vitaminB5": 0,
"vitaminB6": 2.69,
"vitaminB9": 274,
"vitaminB12": 0,
"vitaminC": 32.4,
"vitaminD": 0,
"vitaminE": 7.48,
"vitaminK": 1714.5,
"magnesium": 428,
"calcium": 1652,
"phosphorus": 91,
"potassium": 1070,
"iron": 28.12,
"selenium": 3.7,
"zinc": 4.7,
"manganese": 3.133,
"copper": 0.757,
"choline": 43.6,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 0.7
}
},
{
"id": 5021,
"name": "Dried Parsley",
"categoryId": 5000,
"energy": 292,
"fat": 5.48,
"saturatedFat": 1.378,
"monounsaturatedFat": 0.761,
"polyunsaturatedFat": 3.124,
"carbs": 50.64,
"sugar": 7.27,
"fiber": 26.7,
"protein": 26.63,
"sodium": 452,
"cholesterol": 0,
"vitaminA": 97,
"vitaminB1": 0.196,
"vitaminB2": 2.383,
"vitaminB3": 9.943,
"vitaminB5": 1.062,
"vitaminB6": 0.9,
"vitaminB9": 180,
"vitaminB12": 0,
"vitaminC": 125,
"vitaminD": 0,
"vitaminE": 8.96,
"vitaminK": 1359.5,
"magnesium": 400,
"calcium": 1140,
"phosphorus": 436,
"potassium": 2683,
"iron": 22.04,
"selenium": 14.1,
"zinc": 5.44,
"manganese": 9.81,
"copper": 0.78,
"choline": 97.1,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 0.5
}
},
{
"id": 5022,
"name": "Garlic Powder",
"categoryId": 5000,
"energy": 331,
"fat": 0.73,
"saturatedFat": 0.249,
"monounsaturatedFat": 0.115,
"polyunsaturatedFat": 0.178,
"carbs": 72.73,
"sugar": 2.43,
"fiber": 9,
"protein": 16.55,
"sodium": 60,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.435,
"vitaminB2": 0.141,
"vitaminB3": 0.796,
"vitaminB5": 0.743,
"vitaminB6": 1.654,
"vitaminB9": 47,
"vitaminB12": 0,
"vitaminC": 1.2,
"vitaminD": 0,
"vitaminE": 0.67,
"vitaminK": 0.4,
"magnesium": 77,
"calcium": 79,
"phosphorus": 414,
"potassium": 1193,
"iron": 5.65,
"selenium": 23.9,
"zinc": 2.99,
"manganese": 0.979,
"copper": 0.533,
"choline": 67.5,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 9.7
}
},
{
"id": 5023,
"name": "Cappers",
"categoryId": 5000,
"energy": 23,
"fat": 0.86,
"saturatedFat": 0.233,
"monounsaturatedFat": 0.063,
"polyunsaturatedFat": 0.304,
"carbs": 4.89,
"sugar": 0.41,
"fiber": 3.2,
"protein": 2.36,
"sodium": 2348,
"cholesterol": 0,
"vitaminA": 7,
"vitaminB1": 0.018,
"vitaminB2": 0.139,
"vitaminB3": 0.652,
"vitaminB5": 0.027,
"vitaminB6": 0.023,
"vitaminB9": 23,
"vitaminB12": 0,
"vitaminC": 4.3,
"vitaminD": 0,
"vitaminE": 0.88,
"vitaminK": 24.6,
"magnesium": 33,
"calcium": 40,
"phosphorus": 10,
"potassium": 40,
"iron": 1.67,
"selenium": 1.2,
"zinc": 0.32,
"manganese": 0.078,
"copper": 0.374,
"choline": 6.5,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 8.6
}
},
{
"id": 5024,
"name": "Apple Cider Vinegar",
"categoryId": 5000,
"energy": 21,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 0.93,
"sugar": 0.4,
"fiber": 0,
"protein": 0,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 5,
"calcium": 7,
"phosphorus": 8,
"potassium": 73,
"iron": 0.2,
"selenium": 0.1,
"zinc": 0.04,
"manganese": 0.249,
"copper": 0.008,
"choline": 0,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 5
}
},
{
"id": 5025,
"name": "Salt",
"categoryId": 5000,
"energy": 0,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 0,
"sodium": 38758,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 1,
"calcium": 24,
"phosphorus": 0,
"potassium": 8,
"iron": 0.33,
"selenium": 0.1,
"zinc": 0.1,
"manganese": 0.1,
"copper": 0.03,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 292
}
},
{
"id": 5026,
"name": "Dried Coriander leaves",
"categoryId": 5000,
"energy": 279,
"fat": 4.78,
"saturatedFat": 0.115,
"monounsaturatedFat": 2.232,
"polyunsaturatedFat": 0.328,
"carbs": 52.1,
"sugar": 7.27,
"fiber": 10.4,
"protein": 21.93,
"sodium": 211,
"cholesterol": 0,
"vitaminA": 293,
"vitaminB1": 1.252,
"vitaminB2": 1.5,
"vitaminB3": 10.707,
"vitaminB5": 0,
"vitaminB6": 0.61,
"vitaminB9": 274,
"vitaminB12": 0,
"vitaminC": 566.7,
"vitaminD": 0,
"vitaminE": 1.03,
"vitaminK": 1359.5,
"magnesium": 694,
"calcium": 1246,
"phosphorus": 481,
"potassium": 4466,
"iron": 42.46,
"selenium": 29.3,
"zinc": 4.72,
"manganese": 6.355,
"copper": 1.786,
"choline": 97.1,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 0.6
}
}
]
================================================
FILE: src/foods/builtIn/sweetsAndSnacks.json
================================================
[
{
"id": 6001,
"name": "Maple syrup",
"categoryId": 6000,
"energy": 260,
"fat": 0.06,
"saturatedFat": 0.007,
"monounsaturatedFat": 0.011,
"polyunsaturatedFat": 0.017,
"carbs": 67.04,
"sugar": 60.46,
"fiber": 0,
"protein": 0.04,
"sodium": 12,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.066,
"vitaminB2": 1.27,
"vitaminB3": 0.081,
"vitaminB5": 0.036,
"vitaminB6": 0.002,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 21,
"calcium": 102,
"phosphorus": 2,
"potassium": 212,
"iron": 0.11,
"selenium": 0.6,
"zinc": 1.47,
"manganese": 2.908,
"copper": 0.018,
"choline": 1.6,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 20
}
},
{
"id": 6002,
"name": "Sugar",
"categoryId": 6000,
"energy": 387,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 99.98,
"sugar": 99.8,
"fiber": 0,
"protein": 0,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0.019,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 1,
"phosphorus": 0,
"potassium": 2,
"iron": 0.05,
"selenium": 0.6,
"zinc": 0.01,
"manganese": 0.004,
"copper": 0.007,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 200
}
},
{
"id": 6003,
"name": "Brown sugar",
"categoryId": 6000,
"energy": 380,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 98.09,
"sugar": 97.02,
"fiber": 0,
"protein": 0.12,
"sodium": 28,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0.11,
"vitaminB5": 0.132,
"vitaminB6": 0.041,
"vitaminB9": 1,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 9,
"calcium": 83,
"phosphorus": 4,
"potassium": 133,
"iron": 0.71,
"selenium": 1.2,
"zinc": 0.03,
"manganese": 0.064,
"copper": 0.047,
"choline": 2.3,
"volume": {
"portionId": "cups",
"weightInGrams": 220
}
},
{
"id": 6004,
"name": "Chocolate Chips Cookies",
"categoryId": 6000,
"energy": 492,
"fat": 24.72,
"saturatedFat": 8.091,
"monounsaturatedFat": 6.272,
"polyunsaturatedFat": 8.417,
"carbs": 65.36,
"sugar": 32.9,
"fiber": 2,
"protein": 5.1,
"sodium": 311,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.292,
"vitaminB2": 0.297,
"vitaminB3": 2.665,
"vitaminB5": 0,
"vitaminB6": 0.058,
"vitaminB9": 72,
"vitaminB12": 0.03,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 2.01,
"vitaminK": 33.7,
"magnesium": 41,
"calcium": 21,
"phosphorus": 109,
"potassium": 171,
"iron": 5.58,
"selenium": 3.9,
"zinc": 0.72,
"manganese": 0.62,
"copper": 0.323,
"choline": 10.5
},
{
"id": 6005,
"name": "Agave Syrup",
"categoryId": 6000,
"energy": 310,
"fat": 0.45,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 76.37,
"sugar": 68.03,
"fiber": 0.2,
"protein": 0.09,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 8,
"vitaminB1": 0.122,
"vitaminB2": 0.165,
"vitaminB3": 0.689,
"vitaminB5": 0,
"vitaminB6": 0.234,
"vitaminB9": 30,
"vitaminB12": 0,
"vitaminC": 17,
"vitaminD": 0,
"vitaminE": 0.98,
"vitaminK": 22.5,
"magnesium": 1,
"calcium": 1,
"phosphorus": 1,
"potassium": 4,
"iron": 0.09,
"selenium": 1.7,
"zinc": 0.01,
"manganese": 0.005,
"copper": 0.009,
"choline": 13.3,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 6.9
}
},
{
"id": 6006,
"name": "Honey",
"categoryId": 6000,
"energy": 304,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 82.4,
"sugar": 82.12,
"fiber": 0.2,
"protein": 0.3,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0.038,
"vitaminB3": 0.121,
"vitaminB5": 0.068,
"vitaminB6": 0.024,
"vitaminB9": 2,
"vitaminB12": 0,
"vitaminC": 0.5,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 2,
"calcium": 6,
"phosphorus": 4,
"potassium": 52,
"iron": 0.42,
"selenium": 0.8,
"zinc": 0.22,
"manganese": 0.08,
"copper": 0.036,
"choline": 2.2,
"volume": {
"portionId": "cups",
"weightInGrams": 339
}
},
{
"id": 6007,
"name": "Pancake Syrup",
"categoryId": 6000,
"energy": 234,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 61.47,
"sugar": 21.47,
"fiber": 0,
"protein": 0,
"sodium": 82,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.024,
"vitaminB2": 0.008,
"vitaminB3": 0,
"vitaminB5": 0.004,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 2,
"calcium": 3,
"phosphorus": 9,
"potassium": 15,
"iron": 0.03,
"selenium": 0,
"zinc": 0.08,
"manganese": 0.068,
"copper": 0,
"choline": 0,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 20
}
},
{
"id": 6008,
"name": "Reduced Calorie Pancake Syrup",
"categoryId": 6000,
"energy": 165,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 44.55,
"sugar": 32.8,
"fiber": 0,
"protein": 0,
"sodium": 178,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.025,
"vitaminB2": 0.003,
"vitaminB3": 0.004,
"vitaminB5": 0.005,
"vitaminB6": 0.003,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 2,
"calcium": 10,
"phosphorus": 43,
"potassium": 3,
"iron": 0.03,
"selenium": 0.5,
"zinc": 0.2,
"manganese": 0.022,
"copper": 0.018,
"choline": 0.1,
"volume": {
"portionId": "cups",
"weightInGrams": 240
}
},
{
"id": 6009,
"name": "Jam",
"categoryId": 6000,
"energy": 278,
"fat": 0.07,
"saturatedFat": 0.01,
"monounsaturatedFat": 0.038,
"polyunsaturatedFat": 0,
"carbs": 68.86,
"sugar": 48.5,
"fiber": 1.1,
"protein": 0.37,
"sodium": 32,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.016,
"vitaminB2": 0.076,
"vitaminB3": 0.036,
"vitaminB5": 0.02,
"vitaminB6": 0.02,
"vitaminB9": 11,
"vitaminB12": 0,
"vitaminC": 8.8,
"vitaminD": 0,
"vitaminE": 0.12,
"vitaminK": 0,
"magnesium": 4,
"calcium": 20,
"phosphorus": 19,
"potassium": 77,
"iron": 0.49,
"selenium": 2,
"zinc": 0.06,
"manganese": 0.04,
"copper": 0.1,
"choline": 10.2,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 20
}
},
{
"id": 6010,
"name": "Dark Chocolate (45-59%)",
"categoryId": 6000,
"energy": 546,
"fat": 31.28,
"saturatedFat": 18.519,
"monounsaturatedFat": 9.54,
"polyunsaturatedFat": 1.092,
"carbs": 61.17,
"sugar": 47.9,
"fiber": 7,
"protein": 4.88,
"sodium": 24,
"cholesterol": 8,
"vitaminA": 2,
"vitaminB1": 0.025,
"vitaminB2": 0.05,
"vitaminB3": 0.725,
"vitaminB5": 0.297,
"vitaminB6": 0.042,
"vitaminB9": 0,
"vitaminB12": 0.23,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.54,
"vitaminK": 8.1,
"magnesium": 146,
"calcium": 56,
"phosphorus": 206,
"potassium": 559,
"iron": 8.02,
"selenium": 3,
"zinc": 2.01,
"manganese": 1.419,
"copper": 1.028,
"choline": 0
},
{
"id": 6011,
"name": "Dark Chocolate (60-69%)",
"categoryId": 6000,
"energy": 579,
"fat": 38.31,
"saturatedFat": 22.031,
"monounsaturatedFat": 11.522,
"polyunsaturatedFat": 1.221,
"carbs": 52.42,
"sugar": 36.71,
"fiber": 8,
"protein": 6.12,
"sodium": 10,
"cholesterol": 6,
"vitaminA": 3,
"vitaminB1": 0.032,
"vitaminB2": 0.049,
"vitaminB3": 0.838,
"vitaminB5": 0.3,
"vitaminB6": 0.034,
"vitaminB9": 0,
"vitaminB12": 0.18,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.59,
"vitaminK": 7.2,
"magnesium": 176,
"calcium": 62,
"phosphorus": 260,
"potassium": 567,
"iron": 6.32,
"selenium": 8.4,
"zinc": 2.65,
"manganese": 1.325,
"copper": 1.248,
"choline": 0
},
{
"id": 6012,
"name": "Dark Chocolate (70-85%)",
"categoryId": 6000,
"energy": 598,
"fat": 42.63,
"saturatedFat": 24.489,
"monounsaturatedFat": 12.781,
"polyunsaturatedFat": 1.257,
"carbs": 45.9,
"sugar": 23.99,
"fiber": 10.9,
"protein": 7.79,
"sodium": 20,
"cholesterol": 3,
"vitaminA": 2,
"vitaminB1": 0.034,
"vitaminB2": 0.078,
"vitaminB3": 1.054,
"vitaminB5": 0.418,
"vitaminB6": 0.038,
"vitaminB9": 0,
"vitaminB12": 0.28,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.59,
"vitaminK": 7.3,
"magnesium": 228,
"calcium": 73,
"phosphorus": 308,
"potassium": 715,
"iron": 11.9,
"selenium": 6.8,
"zinc": 3.31,
"manganese": 1.948,
"copper": 1.766,
"choline": 0
},
{
"id": 6013,
"name": "Unsweetened Cocoa Powder",
"categoryId": 6000,
"energy": 228,
"fat": 13.7,
"saturatedFat": 8.07,
"monounsaturatedFat": 4.57,
"polyunsaturatedFat": 0.44,
"carbs": 57.9,
"sugar": 1.75,
"fiber": 37,
"protein": 19.6,
"sodium": 21,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.078,
"vitaminB2": 0.241,
"vitaminB3": 2.185,
"vitaminB5": 0.254,
"vitaminB6": 0.118,
"vitaminB9": 32,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.1,
"vitaminK": 2.5,
"magnesium": 499,
"calcium": 128,
"phosphorus": 734,
"potassium": 1524,
"iron": 13.86,
"selenium": 14.3,
"zinc": 6.81,
"manganese": 3.837,
"copper": 3.788,
"choline": 12,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 5.4
}
},
{
"id": 6014,
"name": "Marshmallows",
"categoryId": 6000,
"energy": 318,
"fat": 0.2,
"saturatedFat": 0.056,
"monounsaturatedFat": 0.08,
"polyunsaturatedFat": 0.047,
"carbs": 81.3,
"sugar": 57.56,
"fiber": 0.1,
"protein": 1.8,
"sodium": 80,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.001,
"vitaminB2": 0.001,
"vitaminB3": 0.078,
"vitaminB5": 0.005,
"vitaminB6": 0.003,
"vitaminB9": 1,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 2,
"calcium": 3,
"phosphorus": 8,
"potassium": 5,
"iron": 0.23,
"selenium": 1.7,
"zinc": 0.04,
"manganese": 0.008,
"copper": 0.097,
"choline": 0.1,
"volume": {
"portionId": "cups",
"weightInGrams": 50
}
},
{
"id": 6015,
"name": "Chocolate Ice Cream",
"categoryId": 6000,
"energy": 216,
"fat": 11,
"saturatedFat": 6.8,
"monounsaturatedFat": 3.21,
"polyunsaturatedFat": 0.41,
"carbs": 28.2,
"sugar": 25.36,
"fiber": 1.2,
"protein": 3.8,
"sodium": 76,
"cholesterol": 34,
"vitaminA": 118,
"vitaminB1": 0.042,
"vitaminB2": 0.194,
"vitaminB3": 0.226,
"vitaminB5": 0,
"vitaminB6": 0.055,
"vitaminB9": 16,
"vitaminB12": 0.29,
"vitaminC": 0.7,
"vitaminD": 0.2,
"vitaminE": 0.3,
"vitaminK": 0.3,
"magnesium": 29,
"calcium": 109,
"phosphorus": 107,
"potassium": 249,
"iron": 0.93,
"selenium": 2.5,
"zinc": 0.58,
"manganese": 0,
"copper": 0.135,
"choline": 22.5
},
{
"id": 6016,
"name": "Vanilla Ice Cream",
"categoryId": 6000,
"energy": 207,
"fat": 11,
"saturatedFat": 6.79,
"monounsaturatedFat": 2.969,
"polyunsaturatedFat": 0.452,
"carbs": 23.6,
"sugar": 21.22,
"fiber": 0.7,
"protein": 3.5,
"sodium": 80,
"cholesterol": 44,
"vitaminA": 118,
"vitaminB1": 0.041,
"vitaminB2": 0.24,
"vitaminB3": 0.116,
"vitaminB5": 0,
"vitaminB6": 0.048,
"vitaminB9": 5,
"vitaminB12": 0.39,
"vitaminC": 0.6,
"vitaminD": 0.2,
"vitaminE": 0.3,
"vitaminK": 0.3,
"magnesium": 14,
"calcium": 128,
"phosphorus": 105,
"potassium": 199,
"iron": 0.09,
"selenium": 1.8,
"zinc": 0.69,
"manganese": 0,
"copper": 0.023,
"choline": 26
},
{
"id": 6017,
"name": "Rice Cakes",
"categoryId": 6000,
"energy": 392,
"fat": 4.3,
"saturatedFat": 0.875,
"monounsaturatedFat": 1.582,
"polyunsaturatedFat": 1.52,
"carbs": 81.1,
"sugar": 0.88,
"fiber": 4.2,
"protein": 7.1,
"sodium": 71,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.06,
"vitaminB2": 0.16,
"vitaminB3": 7.81,
"vitaminB5": 0,
"vitaminB6": 0.15,
"vitaminB9": 21,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 1.24,
"vitaminK": 1.9,
"magnesium": 131,
"calcium": 11,
"phosphorus": 360,
"potassium": 428,
"iron": 1.49,
"selenium": 24.6,
"zinc": 3,
"manganese": 0,
"copper": 0.445,
"choline": 18.9
},
{
"id": 6018,
"name": "Tortilla Chips",
"categoryId": 6000,
"energy": 497,
"fat": 22.33,
"saturatedFat": 2.776,
"monounsaturatedFat": 8.584,
"polyunsaturatedFat": 9.179,
"carbs": 67.38,
"sugar": 1.21,
"fiber": 4.7,
"protein": 6.62,
"sodium": 310,
"cholesterol": 0,
"vitaminA": 8,
"vitaminB1": 0.13,
"vitaminB2": 0.043,
"vitaminB3": 1.498,
"vitaminB5": 0.411,
"vitaminB6": 0.202,
"vitaminB9": 22,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 2.97,
"vitaminK": 0.6,
"magnesium": 84,
"calcium": 104,
"phosphorus": 234,
"potassium": 206,
"iron": 1.32,
"selenium": 8.4,
"zinc": 1.46,
"manganese": 0.357,
"copper": 0.105,
"choline": 19.1
},
{
"id": 6019,
"name": "Air-popped Popcorn",
"categoryId": 6000,
"energy": 387,
"fat": 4.54,
"saturatedFat": 0.637,
"monounsaturatedFat": 0.95,
"polyunsaturatedFat": 2.318,
"carbs": 77.78,
"sugar": 0.87,
"fiber": 14.5,
"protein": 12.94,
"sodium": 8,
"cholesterol": 0,
"vitaminA": 10,
"vitaminB1": 0.104,
"vitaminB2": 0.083,
"vitaminB3": 2.308,
"vitaminB5": 0.51,
"vitaminB6": 0.157,
"vitaminB9": 31,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.29,
"vitaminK": 1.2,
"magnesium": 144,
"calcium": 7,
"phosphorus": 358,
"potassium": 329,
"iron": 3.19,
"selenium": 0,
"zinc": 3.08,
"manganese": 1.113,
"copper": 0.262,
"choline": 21.2,
"volume": {
"portionId": "cups",
"weightInGrams": 8
}
},
{
"id": 6020,
"name": "Pork Rinds",
"categoryId": 6000,
"energy": 544,
"fat": 31.3,
"saturatedFat": 11.37,
"monounsaturatedFat": 14.78,
"polyunsaturatedFat": 3.64,
"carbs": 0,
"sugar": 0,
"fiber": 0,
"protein": 61.3,
"sodium": 1818,
"cholesterol": 95,
"vitaminA": 12,
"vitaminB1": 0.099,
"vitaminB2": 0.283,
"vitaminB3": 1.549,
"vitaminB5": 0,
"vitaminB6": 0.023,
"vitaminB9": 0,
"vitaminB12": 0.64,
"vitaminC": 0.5,
"vitaminD": 0,
"vitaminE": 0.53,
"vitaminK": 0,
"magnesium": 11,
"calcium": 30,
"phosphorus": 85,
"potassium": 127,
"iron": 0.88,
"selenium": 41,
"zinc": 0.56,
"manganese": 0,
"copper": 0.094,
"choline": 164.5
},
{
"id": 6021,
"name": "Sugar Free Chocolate Syrup",
"categoryId": 6000,
"energy": 43,
"fat": 2.03,
"saturatedFat": 0.746,
"monounsaturatedFat": 0.428,
"polyunsaturatedFat": 0.041,
"carbs": 14.2,
"sugar": 0.27,
"fiber": 2.9,
"protein": 2.87,
"sodium": 343,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.017,
"vitaminB2": 0.071,
"vitaminB3": 0.371,
"vitaminB5": 0.039,
"vitaminB6": 0.018,
"vitaminB9": 5,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0.02,
"vitaminK": 0.4,
"magnesium": 74,
"calcium": 0,
"phosphorus": 113,
"potassium": 388,
"iron": 2.06,
"selenium": 2,
"zinc": 0.99,
"manganese": 0.579,
"copper": 0.565,
"choline": 1.8,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 35
}
},
{
"id": 6022,
"name": "Sugar Free Chocolate Chips",
"categoryId": 6000,
"energy": 450,
"fat": 16.8,
"saturatedFat": 4.183,
"monounsaturatedFat": 6.73,
"polyunsaturatedFat": 5.035,
"carbs": 73.4,
"sugar": 39.81,
"fiber": 1.6,
"protein": 3.9,
"sodium": 244,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.373,
"vitaminB2": 0.188,
"vitaminB3": 2.843,
"vitaminB5": 0,
"vitaminB6": 0.018,
"vitaminB9": 54,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 1.06,
"vitaminK": 4,
"magnesium": 21,
"calcium": 46,
"phosphorus": 109,
"potassium": 199,
"iron": 3.5,
"selenium": 2.6,
"zinc": 0.47,
"manganese": 0,
"copper": 0.218,
"choline": 6.7
},
{
"id": 6023,
"name": "Sugar Free Syrup",
"categoryId": 6000,
"energy": 51,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 11.99,
"sugar": 0.01,
"fiber": 0.7,
"protein": 0.8,
"sodium": 210,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0.002,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0.5,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 15
}
},
{
"id": 6024,
"name": "Guar Gum",
"categoryId": 6000,
"energy": 332,
"fat": 0.5,
"saturatedFat": 0.06,
"monounsaturatedFat": 0.22,
"polyunsaturatedFat": 0.07,
"carbs": 77.3,
"sugar": 0,
"fiber": 77.3,
"protein": 4.6,
"sodium": 125,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 294,
"phosphorus": 0,
"potassium": 0,
"iron": 0,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
}
]
================================================
FILE: src/foods/builtIn/vegetables.json
================================================
[
{
"id": 701,
"name": "Sweet Corn Kernels (frozen)",
"categoryId": 700,
"energy": 88,
"fat": 0.78,
"saturatedFat": 0.119,
"monounsaturatedFat": 0.227,
"polyunsaturatedFat": 0.366,
"carbs": 20.71,
"sugar": 2.5,
"fiber": 2.1,
"protein": 3.02,
"sodium": 3,
"cholesterol": 0,
"vitaminA": 10,
"vitaminB1": 0.083,
"vitaminB2": 0.068,
"vitaminB3": 1.739,
"vitaminB5": 0.361,
"vitaminB6": 0.168,
"vitaminB9": 36,
"vitaminB12": 0,
"vitaminC": 6.4,
"vitaminD": 0,
"vitaminE": 0.08,
"vitaminK": 0.3,
"magnesium": 18,
"calcium": 4,
"phosphorus": 70,
"potassium": 213,
"iron": 0.42,
"selenium": 0.7,
"zinc": 0.38,
"manganese": 0.123,
"copper": 0.036,
"choline": 24,
"volume": {
"portionId": "cups",
"weightInGrams": 136
}
},
{
"id": 702,
"name": "Romaine Lettuce",
"categoryId": 700,
"energy": 15,
"fat": 0.15,
"saturatedFat": 0.02,
"monounsaturatedFat": 0.006,
"polyunsaturatedFat": 0.082,
"carbs": 2.87,
"sugar": 0.78,
"fiber": 1.3,
"protein": 1.36,
"sodium": 28,
"cholesterol": 0,
"vitaminA": 370,
"vitaminB1": 0.07,
"vitaminB2": 0.08,
"vitaminB3": 0.375,
"vitaminB5": 0,
"vitaminB6": 0.09,
"vitaminB9": 38,
"vitaminB12": 0,
"vitaminC": 9.2,
"vitaminD": 0,
"vitaminE": 0.22,
"vitaminK": 126.3,
"magnesium": 13,
"calcium": 36,
"phosphorus": 29,
"potassium": 194,
"iron": 0.86,
"selenium": 0.6,
"zinc": 0.18,
"manganese": 0,
"copper": 0.029,
"choline": 13.6
},
{
"id": 703,
"name": "Brussels Sprouts",
"categoryId": 700,
"energy": 43,
"fat": 0.3,
"saturatedFat": 0.062,
"monounsaturatedFat": 0.023,
"polyunsaturatedFat": 0.153,
"carbs": 8.95,
"sugar": 2.2,
"fiber": 3.8,
"protein": 3.38,
"sodium": 25,
"cholesterol": 0,
"vitaminA": 38,
"vitaminB1": 0.139,
"vitaminB2": 0.09,
"vitaminB3": 0.745,
"vitaminB5": 0.309,
"vitaminB6": 0.219,
"vitaminB9": 61,
"vitaminB12": 0,
"vitaminC": 85,
"vitaminD": 0,
"vitaminE": 0.88,
"vitaminK": 177,
"magnesium": 23,
"calcium": 42,
"phosphorus": 69,
"potassium": 389,
"iron": 1.4,
"selenium": 1.6,
"zinc": 0.42,
"manganese": 0.337,
"copper": 0.07,
"choline": 19.1,
"volume": {
"portionId": "cups",
"weightInGrams": 88
}
},
{
"id": 704,
"name": "Carrots",
"categoryId": 700,
"energy": 41,
"fat": 0.24,
"saturatedFat": 0.032,
"monounsaturatedFat": 0.012,
"polyunsaturatedFat": 0.102,
"carbs": 9.58,
"sugar": 4.74,
"fiber": 2.8,
"protein": 0.93,
"sodium": 69,
"cholesterol": 0,
"vitaminA": 835,
"vitaminB1": 0.066,
"vitaminB2": 0.058,
"vitaminB3": 0.983,
"vitaminB5": 0.273,
"vitaminB6": 0.138,
"vitaminB9": 19,
"vitaminB12": 0,
"vitaminC": 5.9,
"vitaminD": 0,
"vitaminE": 0.66,
"vitaminK": 13.2,
"magnesium": 12,
"calcium": 33,
"phosphorus": 35,
"potassium": 320,
"iron": 0.3,
"selenium": 0.1,
"zinc": 0.24,
"manganese": 0.143,
"copper": 0.045,
"choline": 8.8,
"volume": {
"portionId": "cups",
"weightInGrams": 110
}
},
{
"id": 705,
"name": "Frozen Mixed Vegetables",
"categoryId": 700,
"energy": 72,
"fat": 0.52,
"saturatedFat": 0.098,
"monounsaturatedFat": 0.031,
"polyunsaturatedFat": 0.235,
"carbs": 13.47,
"sugar": 0,
"fiber": 4,
"protein": 3.33,
"sodium": 47,
"cholesterol": 0,
"vitaminA": 254,
"vitaminB1": 0.122,
"vitaminB2": 0.085,
"vitaminB3": 1.252,
"vitaminB5": 0.163,
"vitaminB6": 0.096,
"vitaminB9": 29,
"vitaminB12": 0,
"vitaminC": 10.4,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 24,
"calcium": 25,
"phosphorus": 59,
"potassium": 212,
"iron": 0.95,
"selenium": 0.4,
"zinc": 0.45,
"manganese": 0.244,
"copper": 0.093,
"choline": 0
},
{
"id": 706,
"name": "Onions",
"categoryId": 700,
"energy": 40,
"fat": 0.1,
"saturatedFat": 0.042,
"monounsaturatedFat": 0.013,
"polyunsaturatedFat": 0.017,
"carbs": 9.34,
"sugar": 4.24,
"fiber": 1.7,
"protein": 1.1,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.046,
"vitaminB2": 0.027,
"vitaminB3": 0.116,
"vitaminB5": 0.123,
"vitaminB6": 0.12,
"vitaminB9": 19,
"vitaminB12": 0,
"vitaminC": 7.4,
"vitaminD": 0,
"vitaminE": 0.02,
"vitaminK": 0.4,
"magnesium": 10,
"calcium": 23,
"phosphorus": 29,
"potassium": 146,
"iron": 0.21,
"selenium": 0.5,
"zinc": 0.17,
"manganese": 0.129,
"copper": 0.039,
"choline": 6.1,
"volume": {
"portionId": "cups",
"weightInGrams": 160
}
},
{
"id": 707,
"name": "Broccoli",
"categoryId": 700,
"energy": 34,
"fat": 0.37,
"saturatedFat": 0.114,
"monounsaturatedFat": 0.031,
"polyunsaturatedFat": 0.112,
"carbs": 6.64,
"sugar": 1.7,
"fiber": 2.6,
"protein": 2.82,
"sodium": 33,
"cholesterol": 0,
"vitaminA": 31,
"vitaminB1": 0.071,
"vitaminB2": 0.117,
"vitaminB3": 0.639,
"vitaminB5": 0.573,
"vitaminB6": 0.175,
"vitaminB9": 63,
"vitaminB12": 0,
"vitaminC": 89.2,
"vitaminD": 0,
"vitaminE": 0.78,
"vitaminK": 101.6,
"magnesium": 21,
"calcium": 47,
"phosphorus": 66,
"potassium": 316,
"iron": 0.73,
"selenium": 2.5,
"zinc": 0.41,
"manganese": 0.21,
"copper": 0.049,
"choline": 18.7,
"volume": {
"portionId": "cups",
"weightInGrams": 44
}
},
{
"id": 708,
"name": "Green Beans",
"categoryId": 700,
"energy": 31,
"fat": 0.22,
"saturatedFat": 0.05,
"monounsaturatedFat": 0.01,
"polyunsaturatedFat": 0.113,
"carbs": 6.97,
"sugar": 3.26,
"fiber": 2.7,
"protein": 1.83,
"sodium": 6,
"cholesterol": 0,
"vitaminA": 35,
"vitaminB1": 0.082,
"vitaminB2": 0.104,
"vitaminB3": 0.734,
"vitaminB5": 0,
"vitaminB6": 0.141,
"vitaminB9": 33,
"vitaminB12": 0,
"vitaminC": 12.2,
"vitaminD": 0,
"vitaminE": 0.41,
"vitaminK": 43,
"magnesium": 25,
"calcium": 37,
"phosphorus": 38,
"potassium": 211,
"iron": 1.03,
"selenium": 0.6,
"zinc": 0.24,
"manganese": 0,
"copper": 0.069,
"choline": 15.3
},
{
"id": 709,
"name": "Russet Potatoes",
"categoryId": 700,
"energy": 79,
"fat": 0.08,
"saturatedFat": 0.026,
"monounsaturatedFat": 0.002,
"polyunsaturatedFat": 0.043,
"carbs": 18.07,
"sugar": 0.62,
"fiber": 1.3,
"protein": 2.14,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.082,
"vitaminB2": 0.033,
"vitaminB3": 1.035,
"vitaminB5": 0.301,
"vitaminB6": 0.345,
"vitaminB9": 14,
"vitaminB12": 0,
"vitaminC": 5.7,
"vitaminD": 0,
"vitaminE": 0.01,
"vitaminK": 1.8,
"magnesium": 23,
"calcium": 13,
"phosphorus": 55,
"potassium": 417,
"iron": 0.86,
"selenium": 0.4,
"zinc": 0.29,
"manganese": 0.157,
"copper": 0.103,
"choline": 12.6,
"volume": {
"portionId": "cups",
"weightInGrams": 75
}
},
{
"id": 710,
"name": "Spinach",
"categoryId": 700,
"energy": 23,
"fat": 0.39,
"saturatedFat": 0.063,
"monounsaturatedFat": 0.01,
"polyunsaturatedFat": 0.165,
"carbs": 3.63,
"sugar": 0.42,
"fiber": 2.2,
"protein": 2.86,
"sodium": 79,
"cholesterol": 0,
"vitaminA": 469,
"vitaminB1": 0.078,
"vitaminB2": 0.189,
"vitaminB3": 0.724,
"vitaminB5": 0.065,
"vitaminB6": 0.195,
"vitaminB9": 194,
"vitaminB12": 0,
"vitaminC": 28.1,
"vitaminD": 0,
"vitaminE": 2.03,
"vitaminK": 482.9,
"magnesium": 79,
"calcium": 99,
"phosphorus": 49,
"potassium": 558,
"iron": 2.71,
"selenium": 1,
"zinc": 0.53,
"manganese": 0.897,
"copper": 0.13,
"choline": 19.3,
"volume": {
"portionId": "cups",
"weightInGrams": 30
}
},
{
"id": 711,
"name": "Bell Peppers",
"categoryId": 700,
"energy": 18,
"fat": 0,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 4.71,
"sugar": 2.35,
"fiber": 1.2,
"protein": 1.18,
"sodium": 0,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0,
"vitaminB2": 0,
"vitaminB3": 0,
"vitaminB5": 0,
"vitaminB6": 0,
"vitaminB9": 0,
"vitaminB12": 0,
"vitaminC": 77.6,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 0,
"calcium": 0,
"phosphorus": 0,
"potassium": 0,
"iron": 0.42,
"selenium": 0,
"zinc": 0,
"manganese": 0,
"copper": 0,
"choline": 0
},
{
"id": 712,
"name": "Celery",
"categoryId": 700,
"energy": 14,
"fat": 0.17,
"saturatedFat": 0.042,
"monounsaturatedFat": 0.032,
"polyunsaturatedFat": 0.079,
"carbs": 2.97,
"sugar": 1.34,
"fiber": 1.6,
"protein": 0.69,
"sodium": 80,
"cholesterol": 0,
"vitaminA": 22,
"vitaminB1": 0.021,
"vitaminB2": 0.057,
"vitaminB3": 0.32,
"vitaminB5": 0.246,
"vitaminB6": 0.074,
"vitaminB9": 36,
"vitaminB12": 0,
"vitaminC": 3.1,
"vitaminD": 0,
"vitaminE": 0.27,
"vitaminK": 29.3,
"magnesium": 11,
"calcium": 40,
"phosphorus": 24,
"potassium": 260,
"iron": 0.2,
"selenium": 0.4,
"zinc": 0.13,
"manganese": 0.103,
"copper": 0.035,
"choline": 6.1,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 7.5
}
},
{
"id": 713,
"name": "Cabbage",
"categoryId": 700,
"energy": 25,
"fat": 0.1,
"saturatedFat": 0.034,
"monounsaturatedFat": 0.017,
"polyunsaturatedFat": 0.017,
"carbs": 5.8,
"sugar": 3.2,
"fiber": 2.5,
"protein": 1.28,
"sodium": 18,
"cholesterol": 0,
"vitaminA": 5,
"vitaminB1": 0.061,
"vitaminB2": 0.04,
"vitaminB3": 0.234,
"vitaminB5": 0.212,
"vitaminB6": 0.124,
"vitaminB9": 43,
"vitaminB12": 0,
"vitaminC": 36.6,
"vitaminD": 0,
"vitaminE": 0.15,
"vitaminK": 76,
"magnesium": 12,
"calcium": 40,
"phosphorus": 26,
"potassium": 170,
"iron": 0.47,
"selenium": 0.3,
"zinc": 0.18,
"manganese": 0.16,
"copper": 0.019,
"choline": 10.7,
"volume": {
"portionId": "cups",
"weightInGrams": 89
}
},
{
"id": 714,
"name": "White Mushrooms",
"categoryId": 700,
"energy": 22,
"fat": 0.34,
"saturatedFat": 0.05,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0.16,
"carbs": 3.26,
"sugar": 1.98,
"fiber": 1,
"protein": 3.09,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.081,
"vitaminB2": 0.402,
"vitaminB3": 3.607,
"vitaminB5": 1.497,
"vitaminB6": 0.104,
"vitaminB9": 17,
"vitaminB12": 0.04,
"vitaminC": 2.1,
"vitaminD": 0.2,
"vitaminE": 0.01,
"vitaminK": 0,
"magnesium": 9,
"calcium": 3,
"phosphorus": 86,
"potassium": 318,
"iron": 0.5,
"selenium": 9.3,
"zinc": 0.52,
"manganese": 0.047,
"copper": 0.318,
"choline": 17.3,
"volume": {
"portionId": "cups",
"weightInGrams": 70
}
},
{
"id": 715,
"name": "Cucumber (peeled)",
"categoryId": 700,
"energy": 10,
"fat": 0.16,
"saturatedFat": 0.078,
"monounsaturatedFat": 0.01,
"polyunsaturatedFat": 0.019,
"carbs": 2.16,
"sugar": 1.38,
"fiber": 0.7,
"protein": 0.59,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 4,
"vitaminB1": 0.031,
"vitaminB2": 0.025,
"vitaminB3": 0.037,
"vitaminB5": 0.24,
"vitaminB6": 0.051,
"vitaminB9": 14,
"vitaminB12": 0,
"vitaminC": 3.2,
"vitaminD": 0,
"vitaminE": 0.03,
"vitaminK": 7.2,
"magnesium": 12,
"calcium": 14,
"phosphorus": 21,
"potassium": 136,
"iron": 0.22,
"selenium": 0.1,
"zinc": 0.17,
"manganese": 0.073,
"copper": 0.071,
"choline": 5.7,
"volume": {
"portionId": "cups",
"weightInGrams": 119
}
},
{
"id": 716,
"name": "Cucumber (with peel)",
"categoryId": 700,
"energy": 15,
"fat": 0.11,
"saturatedFat": 0.037,
"monounsaturatedFat": 0.005,
"polyunsaturatedFat": 0.032,
"carbs": 3.63,
"sugar": 1.67,
"fiber": 0.5,
"protein": 0.65,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 5,
"vitaminB1": 0.027,
"vitaminB2": 0.033,
"vitaminB3": 0.098,
"vitaminB5": 0.259,
"vitaminB6": 0.04,
"vitaminB9": 7,
"vitaminB12": 0,
"vitaminC": 2.8,
"vitaminD": 0,
"vitaminE": 0.03,
"vitaminK": 16.4,
"magnesium": 13,
"calcium": 16,
"phosphorus": 24,
"potassium": 147,
"iron": 0.28,
"selenium": 0.3,
"zinc": 0.2,
"manganese": 0.079,
"copper": 0.041,
"choline": 6,
"volume": {
"portionId": "cups",
"weightInGrams": 52
}
},
{
"id": 717,
"name": "Eggplant",
"categoryId": 700,
"energy": 25,
"fat": 0.18,
"saturatedFat": 0.034,
"monounsaturatedFat": 0.016,
"polyunsaturatedFat": 0.076,
"carbs": 5.88,
"sugar": 3.53,
"fiber": 3,
"protein": 0.98,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.039,
"vitaminB2": 0.037,
"vitaminB3": 0.649,
"vitaminB5": 0.281,
"vitaminB6": 0.084,
"vitaminB9": 22,
"vitaminB12": 0,
"vitaminC": 2.2,
"vitaminD": 0,
"vitaminE": 0.3,
"vitaminK": 3.5,
"magnesium": 14,
"calcium": 9,
"phosphorus": 24,
"potassium": 229,
"iron": 0.23,
"selenium": 0.3,
"zinc": 0.16,
"manganese": 0.232,
"copper": 0.081,
"choline": 6.9,
"volume": {
"portionId": "cups",
"weightInGrams": 82
}
},
{
"id": 718,
"name": "Peas",
"categoryId": 700,
"energy": 81,
"fat": 0.4,
"saturatedFat": 0.071,
"monounsaturatedFat": 0.035,
"polyunsaturatedFat": 0.187,
"carbs": 14.45,
"sugar": 5.67,
"fiber": 5.7,
"protein": 5.42,
"sodium": 5,
"cholesterol": 0,
"vitaminA": 38,
"vitaminB1": 0.266,
"vitaminB2": 0.132,
"vitaminB3": 2.09,
"vitaminB5": 0.104,
"vitaminB6": 0.169,
"vitaminB9": 65,
"vitaminB12": 0,
"vitaminC": 40,
"vitaminD": 0,
"vitaminE": 0.13,
"vitaminK": 24.8,
"magnesium": 33,
"calcium": 25,
"phosphorus": 108,
"potassium": 244,
"iron": 1.47,
"selenium": 1.8,
"zinc": 1.24,
"manganese": 0.41,
"copper": 0.176,
"choline": 28.4,
"volume": {
"portionId": "cups",
"weightInGrams": 145
}
},
{
"id": 719,
"name": "Butternut Squash",
"categoryId": 700,
"energy": 45,
"fat": 0.1,
"saturatedFat": 0.021,
"monounsaturatedFat": 0.007,
"polyunsaturatedFat": 0.042,
"carbs": 11.69,
"sugar": 2.2,
"fiber": 2,
"protein": 1,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 532,
"vitaminB1": 0.1,
"vitaminB2": 0.02,
"vitaminB3": 1.2,
"vitaminB5": 0.4,
"vitaminB6": 0.154,
"vitaminB9": 27,
"vitaminB12": 0,
"vitaminC": 21,
"vitaminD": 0,
"vitaminE": 1.44,
"vitaminK": 1.1,
"magnesium": 34,
"calcium": 48,
"phosphorus": 33,
"potassium": 352,
"iron": 0.7,
"selenium": 0.5,
"zinc": 0.15,
"manganese": 0.202,
"copper": 0.072,
"choline": 0,
"volume": {
"portionId": "cups",
"weightInGrams": 140
}
},
{
"id": 720,
"name": "Sweet Potatoes",
"categoryId": 700,
"energy": 86,
"fat": 0.05,
"saturatedFat": 0.018,
"monounsaturatedFat": 0.001,
"polyunsaturatedFat": 0.014,
"carbs": 20.12,
"sugar": 4.18,
"fiber": 3,
"protein": 1.57,
"sodium": 55,
"cholesterol": 0,
"vitaminA": 709,
"vitaminB1": 0.078,
"vitaminB2": 0.061,
"vitaminB3": 0.557,
"vitaminB5": 0.8,
"vitaminB6": 0.209,
"vitaminB9": 11,
"vitaminB12": 0,
"vitaminC": 2.4,
"vitaminD": 0,
"vitaminE": 0.26,
"vitaminK": 1.8,
"magnesium": 25,
"calcium": 30,
"phosphorus": 47,
"potassium": 337,
"iron": 0.61,
"selenium": 0.6,
"zinc": 0.3,
"manganese": 0.258,
"copper": 0.151,
"choline": 12.3,
"volume": {
"portionId": "cups",
"weightInGrams": 133
}
},
{
"id": 721,
"name": "Zucchini",
"categoryId": 700,
"energy": 21,
"fat": 0.4,
"saturatedFat": 0.083,
"monounsaturatedFat": 0.031,
"polyunsaturatedFat": 0.169,
"carbs": 3.11,
"sugar": 0,
"fiber": 1.1,
"protein": 2.71,
"sodium": 3,
"cholesterol": 0,
"vitaminA": 25,
"vitaminB1": 0.042,
"vitaminB2": 0.036,
"vitaminB3": 0.705,
"vitaminB5": 0.367,
"vitaminB6": 0.142,
"vitaminB9": 20,
"vitaminB12": 0,
"vitaminC": 34.1,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 33,
"calcium": 21,
"phosphorus": 93,
"potassium": 459,
"iron": 0.79,
"selenium": 0.3,
"zinc": 0.83,
"manganese": 0.196,
"copper": 0.097,
"choline": 0
},
{
"id": 722,
"name": "Cauliflower",
"categoryId": 700,
"energy": 25,
"fat": 0.28,
"saturatedFat": 0.13,
"monounsaturatedFat": 0.034,
"polyunsaturatedFat": 0.031,
"carbs": 4.97,
"sugar": 1.91,
"fiber": 2,
"protein": 1.92,
"sodium": 30,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.05,
"vitaminB2": 0.06,
"vitaminB3": 0.507,
"vitaminB5": 0.667,
"vitaminB6": 0.184,
"vitaminB9": 57,
"vitaminB12": 0,
"vitaminC": 48.2,
"vitaminD": 0,
"vitaminE": 0.08,
"vitaminK": 15.5,
"magnesium": 15,
"calcium": 22,
"phosphorus": 44,
"potassium": 299,
"iron": 0.42,
"selenium": 0.6,
"zinc": 0.27,
"manganese": 0.155,
"copper": 0.039,
"choline": 44.3,
"volume": {
"portionId": "cups",
"weightInGrams": 107
}
},
{
"id": 723,
"name": "Summer Squash",
"categoryId": 700,
"energy": 16,
"fat": 0.18,
"saturatedFat": 0.044,
"monounsaturatedFat": 0.016,
"polyunsaturatedFat": 0.089,
"carbs": 3.35,
"sugar": 2.2,
"fiber": 1.1,
"protein": 1.21,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 10,
"vitaminB1": 0.048,
"vitaminB2": 0.142,
"vitaminB3": 0.487,
"vitaminB5": 0.155,
"vitaminB6": 0.218,
"vitaminB9": 29,
"vitaminB12": 0,
"vitaminC": 17,
"vitaminD": 0,
"vitaminE": 0.12,
"vitaminK": 3,
"magnesium": 17,
"calcium": 15,
"phosphorus": 38,
"potassium": 262,
"iron": 0.35,
"selenium": 0.2,
"zinc": 0.29,
"manganese": 0.175,
"copper": 0.051,
"choline": 6.7,
"volume": {
"portionId": "cups",
"weightInGrams": 113
}
},
{
"id": 724,
"name": "Asparagus",
"categoryId": 700,
"energy": 20,
"fat": 0.12,
"saturatedFat": 0.04,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0.05,
"carbs": 3.88,
"sugar": 1.88,
"fiber": 2.1,
"protein": 2.2,
"sodium": 2,
"cholesterol": 0,
"vitaminA": 38,
"vitaminB1": 0.143,
"vitaminB2": 0.141,
"vitaminB3": 0.978,
"vitaminB5": 0.274,
"vitaminB6": 0.091,
"vitaminB9": 52,
"vitaminB12": 0,
"vitaminC": 5.6,
"vitaminD": 0,
"vitaminE": 1.13,
"vitaminK": 41.6,
"magnesium": 14,
"calcium": 24,
"phosphorus": 52,
"potassium": 202,
"iron": 2.14,
"selenium": 2.3,
"zinc": 0.54,
"manganese": 0.158,
"copper": 0.189,
"choline": 16,
"volume": {
"portionId": "cups",
"weightInGrams": 134
}
},
{
"id": 725,
"name": "Shiitake Mushrooms",
"categoryId": 700,
"energy": 34,
"fat": 0.49,
"saturatedFat": 0,
"monounsaturatedFat": 0,
"polyunsaturatedFat": 0,
"carbs": 6.79,
"sugar": 2.38,
"fiber": 2.5,
"protein": 2.24,
"sodium": 9,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.015,
"vitaminB2": 0.217,
"vitaminB3": 3.877,
"vitaminB5": 1.5,
"vitaminB6": 0.293,
"vitaminB9": 13,
"vitaminB12": 0,
"vitaminC": 0,
"vitaminD": 0.4,
"vitaminE": 0,
"vitaminK": 0,
"magnesium": 20,
"calcium": 2,
"phosphorus": 112,
"potassium": 304,
"iron": 0.41,
"selenium": 5.7,
"zinc": 1.03,
"manganese": 0.23,
"copper": 0.142,
"choline": 0
},
{
"id": 726,
"name": "Jalapeño Peppers",
"categoryId": 700,
"energy": 29,
"fat": 0.37,
"saturatedFat": 0.092,
"monounsaturatedFat": 0.029,
"polyunsaturatedFat": 0.112,
"carbs": 6.5,
"sugar": 4.12,
"fiber": 2.8,
"protein": 0.91,
"sodium": 3,
"cholesterol": 0,
"vitaminA": 54,
"vitaminB1": 0.04,
"vitaminB2": 0.07,
"vitaminB3": 1.28,
"vitaminB5": 0.315,
"vitaminB6": 0.419,
"vitaminB9": 27,
"vitaminB12": 0,
"vitaminC": 118.6,
"vitaminD": 0,
"vitaminE": 3.58,
"vitaminK": 18.5,
"magnesium": 15,
"calcium": 12,
"phosphorus": 26,
"potassium": 248,
"iron": 0.25,
"selenium": 0.4,
"zinc": 0.14,
"manganese": 0.097,
"copper": 0.046,
"choline": 7.5,
"volume": {
"portionId": "cups",
"weightInGrams": 90
}
},
{
"id": 727,
"name": "Kale",
"categoryId": 700,
"energy": 35,
"fat": 1.49,
"saturatedFat": 0.178,
"monounsaturatedFat": 0.104,
"polyunsaturatedFat": 0.673,
"carbs": 4.42,
"sugar": 0.99,
"fiber": 4.1,
"protein": 2.92,
"sodium": 53,
"cholesterol": 0,
"vitaminA": 241,
"vitaminB1": 0.113,
"vitaminB2": 0.347,
"vitaminB3": 1.18,
"vitaminB5": 0.37,
"vitaminB6": 0.147,
"vitaminB9": 62,
"vitaminB12": 0,
"vitaminC": 93.4,
"vitaminD": 0,
"vitaminE": 0.66,
"vitaminK": 389.6,
"magnesium": 33,
"calcium": 254,
"phosphorus": 55,
"potassium": 348,
"iron": 1.6,
"selenium": 0.9,
"zinc": 0.39,
"manganese": 0.92,
"copper": 0.053,
"choline": 0.5,
"volume": {
"portionId": "cups",
"weightInGrams": 21
}
},
{
"id": 728,
"name": "Red Peppers",
"categoryId": 700,
"energy": 26,
"fat": 0.3,
"saturatedFat": 0.059,
"monounsaturatedFat": 0.007,
"polyunsaturatedFat": 0.156,
"carbs": 6.03,
"sugar": 4.2,
"fiber": 2.1,
"protein": 0.99,
"sodium": 4,
"cholesterol": 0,
"vitaminA": 157,
"vitaminB1": 0.054,
"vitaminB2": 0.085,
"vitaminB3": 0.979,
"vitaminB5": 0.317,
"vitaminB6": 0.291,
"vitaminB9": 46,
"vitaminB12": 0,
"vitaminC": 127.7,
"vitaminD": 0,
"vitaminE": 1.58,
"vitaminK": 4.9,
"magnesium": 12,
"calcium": 7,
"phosphorus": 26,
"potassium": 211,
"iron": 0.43,
"selenium": 0.1,
"zinc": 0.25,
"manganese": 0.112,
"copper": 0.017,
"choline": 5.6,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 9.3
}
},
{
"id": 729,
"name": "Radishes",
"categoryId": 700,
"energy": 16,
"fat": 0.1,
"saturatedFat": 0.032,
"monounsaturatedFat": 0.017,
"polyunsaturatedFat": 0.048,
"carbs": 3.4,
"sugar": 1.86,
"fiber": 1.6,
"protein": 0.68,
"sodium": 39,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.012,
"vitaminB2": 0.039,
"vitaminB3": 0.254,
"vitaminB5": 0.165,
"vitaminB6": 0.071,
"vitaminB9": 25,
"vitaminB12": 0,
"vitaminC": 14.8,
"vitaminD": 0,
"vitaminE": 0,
"vitaminK": 1.3,
"magnesium": 10,
"calcium": 25,
"phosphorus": 20,
"potassium": 233,
"iron": 0.34,
"selenium": 0.6,
"zinc": 0.28,
"manganese": 0.069,
"copper": 0.05,
"choline": 6.5,
"volume": {
"portionId": "cups",
"weightInGrams": 116
}
},
{
"id": 730,
"name": "Artichokes",
"categoryId": 700,
"energy": 47,
"fat": 0.15,
"saturatedFat": 0.036,
"monounsaturatedFat": 0.005,
"polyunsaturatedFat": 0.064,
"carbs": 10.51,
"sugar": 0.99,
"fiber": 5.4,
"protein": 3.27,
"sodium": 94,
"cholesterol": 0,
"vitaminA": 1,
"vitaminB1": 0.072,
"vitaminB2": 0.066,
"vitaminB3": 1.046,
"vitaminB5": 0.338,
"vitaminB6": 0.116,
"vitaminB9": 68,
"vitaminB12": 0,
"vitaminC": 11.7,
"vitaminD": 0,
"vitaminE": 0.19,
"vitaminK": 14.8,
"magnesium": 60,
"calcium": 44,
"phosphorus": 90,
"potassium": 370,
"iron": 1.28,
"selenium": 0.2,
"zinc": 0.49,
"manganese": 0.256,
"copper": 0.231,
"choline": 34.4
},
{
"id": 731,
"name": "Chicory",
"categoryId": 700,
"energy": 23,
"fat": 0.3,
"saturatedFat": 0.073,
"monounsaturatedFat": 0.006,
"polyunsaturatedFat": 0.131,
"carbs": 4.7,
"sugar": 0.7,
"fiber": 4,
"protein": 1.7,
"sodium": 45,
"cholesterol": 0,
"vitaminA": 286,
"vitaminB1": 0.06,
"vitaminB2": 0.1,
"vitaminB3": 0.5,
"vitaminB5": 1.159,
"vitaminB6": 0.105,
"vitaminB9": 110,
"vitaminB12": 0,
"vitaminC": 24,
"vitaminD": 0,
"vitaminE": 2.26,
"vitaminK": 297.6,
"magnesium": 30,
"calcium": 100,
"phosphorus": 47,
"potassium": 420,
"iron": 0.9,
"selenium": 0.3,
"zinc": 0.42,
"manganese": 0.429,
"copper": 0.295,
"choline": 12.8,
"volume": {
"portionId": "cups",
"weightInGrams": 29
}
},
{
"id": 732,
"name": "Arugula",
"categoryId": 700,
"energy": 25,
"fat": 0.66,
"saturatedFat": 0.086,
"monounsaturatedFat": 0.049,
"polyunsaturatedFat": 0.319,
"carbs": 3.65,
"sugar": 2.05,
"fiber": 1.6,
"protein": 2.58,
"sodium": 27,
"cholesterol": 0,
"vitaminA": 119,
"vitaminB1": 0.044,
"vitaminB2": 0.086,
"vitaminB3": 0.305,
"vitaminB5": 0.437,
"vitaminB6": 0.073,
"vitaminB9": 97,
"vitaminB12": 0,
"vitaminC": 15,
"vitaminD": 0,
"vitaminE": 0.43,
"vitaminK": 108.6,
"magnesium": 47,
"calcium": 160,
"phosphorus": 52,
"potassium": 369,
"iron": 1.46,
"selenium": 0.3,
"zinc": 0.47,
"manganese": 0.321,
"copper": 0.076,
"choline": 15.3,
"volume": {
"portionId": "cups",
"weightInGrams": 10
}
},
{
"id": 733,
"name": "Pumpkin",
"categoryId": 700,
"energy": 26,
"fat": 0.1,
"saturatedFat": 0.052,
"monounsaturatedFat": 0.013,
"polyunsaturatedFat": 0.005,
"carbs": 6.5,
"sugar": 2.76,
"fiber": 0.5,
"protein": 1,
"sodium": 1,
"cholesterol": 0,
"vitaminA": 426,
"vitaminB1": 0.05,
"vitaminB2": 0.11,
"vitaminB3": 0.6,
"vitaminB5": 0.298,
"vitaminB6": 0.061,
"vitaminB9": 16,
"vitaminB12": 0,
"vitaminC": 9,
"vitaminD": 0,
"vitaminE": 1.06,
"vitaminK": 1.1,
"magnesium": 12,
"calcium": 21,
"phosphorus": 44,
"potassium": 340,
"iron": 0.8,
"selenium": 0.3,
"zinc": 0.32,
"manganese": 0.125,
"copper": 0.127,
"choline": 8.2,
"volume": {
"portionId": "cups",
"weightInGrams": 116
}
},
{
"id": 734,
"name": "Turnips",
"categoryId": 700,
"energy": 28,
"fat": 0.1,
"saturatedFat": 0.011,
"monounsaturatedFat": 0.006,
"polyunsaturatedFat": 0.053,
"carbs": 6.43,
"sugar": 3.8,
"fiber": 1.8,
"protein": 0.9,
"sodium": 67,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.04,
"vitaminB2": 0.03,
"vitaminB3": 0.4,
"vitaminB5": 0.2,
"vitaminB6": 0.09,
"vitaminB9": 15,
"vitaminB12": 0,
"vitaminC": 21,
"vitaminD": 0,
"vitaminE": 0.03,
"vitaminK": 0.1,
"magnesium": 11,
"calcium": 30,
"phosphorus": 27,
"potassium": 191,
"iron": 0.3,
"selenium": 0.7,
"zinc": 0.27,
"manganese": 0.134,
"copper": 0.085,
"choline": 11.1,
"volume": {
"portionId": "cups",
"weightInGrams": 130
}
},
{
"id": 735,
"name": "Scallions",
"categoryId": 700,
"energy": 32,
"fat": 0.19,
"saturatedFat": 0.032,
"monounsaturatedFat": 0.027,
"polyunsaturatedFat": 0.074,
"carbs": 7.34,
"sugar": 2.33,
"fiber": 2.6,
"protein": 1.83,
"sodium": 16,
"cholesterol": 0,
"vitaminA": 50,
"vitaminB1": 0.055,
"vitaminB2": 0.08,
"vitaminB3": 0.525,
"vitaminB5": 0.075,
"vitaminB6": 0.061,
"vitaminB9": 64,
"vitaminB12": 0,
"vitaminC": 18.8,
"vitaminD": 0,
"vitaminE": 0.55,
"vitaminK": 207,
"magnesium": 20,
"calcium": 72,
"phosphorus": 37,
"potassium": 276,
"iron": 1.48,
"selenium": 0.6,
"zinc": 0.39,
"manganese": 0.16,
"copper": 0.083,
"choline": 5.7,
"volume": {
"portionId": "tablespoons",
"weightInGrams": 6
}
},
{
"id": 736,
"name": "Iceberg Lettuce",
"categoryId": 700,
"energy": 14,
"fat": 0.14,
"saturatedFat": 0.018,
"monounsaturatedFat": 0.006,
"polyunsaturatedFat": 0.074,
"carbs": 2.97,
"sugar": 1.97,
"fiber": 1.2,
"protein": 0.9,
"sodium": 10,
"cholesterol": 0,
"vitaminA": 25,
"vitaminB1": 0.041,
"vitaminB2": 0.025,
"vitaminB3": 0.123,
"vitaminB5": 0.091,
"vitaminB6": 0.042,
"vitaminB9": 29,
"vitaminB12": 0,
"vitaminC": 2.8,
"vitaminD": 0,
"vitaminE": 0.18,
"vitaminK": 24.1,
"magnesium": 7,
"calcium": 18,
"phosphorus": 20,
"potassium": 141,
"iron": 0.41,
"selenium": 0.1,
"zinc": 0.15,
"manganese": 0.125,
"copper": 0.025,
"choline": 6.7,
"volume": {
"portionId": "cups",
"weightInGrams": 57
}
},
{
"id": 737,
"name": "Ginger Root",
"categoryId": 700,
"energy": 80,
"fat": 0.75,
"saturatedFat": 0.203,
"monounsaturatedFat": 0.154,
"polyunsaturatedFat": 0.154,
"carbs": 17.77,
"sugar": 1.7,
"fiber": 2,
"protein": 1.82,
"sodium": 13,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.025,
"vitaminB2": 0.034,
"vitaminB3": 0.75,
"vitaminB5": 0.203,
"vitaminB6": 0.16,
"vitaminB9": 11,
"vitaminB12": 0,
"vitaminC": 5,
"vitaminD": 0,
"vitaminE": 0.26,
"vitaminK": 0.1,
"magnesium": 43,
"calcium": 16,
"phosphorus": 34,
"potassium": 415,
"iron": 0.6,
"selenium": 0.7,
"zinc": 0.34,
"manganese": 0.229,
"copper": 0.226,
"choline": 28.8,
"volume": {
"portionId": "cups",
"weightInGrams": 24
}
},
{
"id": 738,
"name": "Red Potatoes",
"categoryId": 700,
"energy": 70,
"fat": 0.14,
"saturatedFat": 0.035,
"monounsaturatedFat": 0.003,
"polyunsaturatedFat": 0.059,
"carbs": 15.9,
"sugar": 1.29,
"fiber": 1.7,
"protein": 1.89,
"sodium": 18,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.081,
"vitaminB2": 0.031,
"vitaminB3": 1.149,
"vitaminB5": 0.279,
"vitaminB6": 0.17,
"vitaminB9": 18,
"vitaminB12": 0,
"vitaminC": 8.6,
"vitaminD": 0,
"vitaminE": 0.01,
"vitaminK": 2.9,
"magnesium": 22,
"calcium": 10,
"phosphorus": 61,
"potassium": 455,
"iron": 0.73,
"selenium": 0.5,
"zinc": 0.33,
"manganese": 0.141,
"copper": 0.134,
"choline": 16.4,
"volume": {
"portionId": "cups",
"weightInGrams": 75
}
},
{
"id": 739,
"name": "Veggie Burger",
"categoryId": 700,
"energy": 177,
"fat": 6.3,
"saturatedFat": 1.44,
"monounsaturatedFat": 1.778,
"polyunsaturatedFat": 2.023,
"carbs": 14.27,
"sugar": 1.07,
"fiber": 4.9,
"protein": 15.7,
"sodium": 569,
"cholesterol": 5,
"vitaminA": 1,
"vitaminB1": 2.651,
"vitaminB2": 0.244,
"vitaminB3": 3.753,
"vitaminB5": 0,
"vitaminB6": 0.303,
"vitaminB9": 124,
"vitaminB12": 2.01,
"vitaminC": 4.5,
"vitaminD": 0,
"vitaminE": 0.23,
"vitaminK": 4.2,
"magnesium": 56,
"calcium": 136,
"phosphorus": 206,
"potassium": 333,
"iron": 2.41,
"selenium": 22.6,
"zinc": 1.26,
"manganese": 0,
"copper": 0.2,
"choline": 19.4
},
{
"id": 740,
"name": "Pumpkin (canned)",
"categoryId": 700,
"energy": 34,
"fat": 0.28,
"saturatedFat": 0.146,
"monounsaturatedFat": 0.037,
"polyunsaturatedFat": 0.015,
"carbs": 8.09,
"sugar": 3.3,
"fiber": 2.9,
"protein": 1.1,
"sodium": 241,
"cholesterol": 0,
"vitaminA": 778,
"vitaminB1": 0.024,
"vitaminB2": 0.054,
"vitaminB3": 0.367,
"vitaminB5": 0.4,
"vitaminB6": 0.056,
"vitaminB9": 12,
"vitaminB12": 0,
"vitaminC": 4.2,
"vitaminD": 0,
"vitaminE": 1.06,
"vitaminK": 16,
"magnesium": 23,
"calcium": 26,
"phosphorus": 35,
"potassium": 206,
"iron": 1.39,
"selenium": 0.4,
"zinc": 0.17,
"manganese": 0.149,
"copper": 0.107,
"choline": 9.8,
"volume": {
"portionId": "cups",
"weightInGrams": 245
}
},
{
"id": 741,
"name": "Chives",
"categoryId": 700,
"energy": 30,
"fat": 0.73,
"saturatedFat": 0.146,
"monounsaturatedFat": 0.095,
"polyunsaturatedFat": 0.267,
"carbs": 4.35,
"sugar": 1.85,
"fiber": 2.5,
"protein": 3.27,
"sodium": 3,
"cholesterol": 0,
"vitaminA": 218,
"vitaminB1": 0.078,
"vitaminB2": 0.115,
"vitaminB3": 0.647,
"vitaminB5": 0.324,
"vitaminB6": 0.138,
"vitaminB9": 105,
"vitaminB12": 0,
"vitaminC": 58.1,
"vitaminD": 0,
"vitaminE": 0.21,
"vitaminK": 212.7,
"magnesium": 42,
"calcium": 92,
"phosphorus": 58,
"potassium": 296,
"iron": 1.6,
"selenium": 0.9,
"zinc": 0.56,
"manganese": 0.373,
"copper": 0.157,
"choline": 5.2,
"volume": {
"portionId": "teaspoons",
"weightInGrams": 1
}
},
{
"id": 742,
"name": "White Potatoes",
"categoryId": 700,
"energy": 69,
"fat": 0.1,
"saturatedFat": 0.026,
"monounsaturatedFat": 0.002,
"polyunsaturatedFat": 0.043,
"carbs": 15.71,
"sugar": 1.15,
"fiber": 2.4,
"protein": 1.68,
"sodium": 16,
"cholesterol": 0,
"vitaminA": 0,
"vitaminB1": 0.071,
"vitaminB2": 0.034,
"vitaminB3": 1.066,
"vitaminB5": 0.281,
"vitaminB6": 0.203,
"vitaminB9": 18,
"vitaminB12": 0,
"vitaminC": 9.1,
"vitaminD": 0,
"vitaminE": 0.01,
"vitaminK": 1.6,
"magnesium": 21,
"calcium": 9,
"phosphorus": 62,
"potassium": 407,
"iron": 0.52,
"selenium": 0.3,
"zinc": 0.29,
"manganese": 0.145,
"copper": 0.116,
"choline": 11,
"volume": {
"portionId": "cups",
"weightInGrams": 75
}
}
]
================================================
FILE: src/foods/foodForm.ts
================================================
import { Food, FoodId } from 'foods'
import { useForm } from 'react-hook-form'
import { object, string, number } from 'yup'
import { objectFromNutritionDataKeys, MappedNutritionData } from 'stats'
import { FoodVolumeForm, getFoodVolumeForm } from './foodVolumeForm'
type FoodForm = {
id?: FoodId
name: string
categoryId: number
servingSizeInGrams: string
volumeForm: FoodVolumeForm
url?: string
} & MappedNutritionData
const DEFAULT_SERVING_SIZE_IN_GRAMS = 100
function getFoodForm(food?: Food) {
const volumeForm = getFoodVolumeForm(food?.volume)
if (food) {
const servingSizeInGrams =
food.servingSizeInGrams || DEFAULT_SERVING_SIZE_IN_GRAMS
return {
id: food.id,
name: food.name,
categoryId: food.categoryId,
servingSizeInGrams: servingSizeInGrams.toString(),
volumeForm,
url: food.url,
...objectFromNutritionDataKeys(key => food[key].toString()),
}
}
return {
name: '',
categoryId: 0,
servingSizeInGrams: DEFAULT_SERVING_SIZE_IN_GRAMS.toString(),
...objectFromNutritionDataKeys(() => '0'),
energy: '',
volumeForm,
}
}
type FoodFormSchemaContext = {
allFoods: Food[]
food?: Food
}
const foodFormSchema = object().shape({
name: string()
.required('Please add a name')
.test(
'uniqueName',
'This name has already been used',
(currentName, { options }) => {
if (currentName === undefined) {
return true
}
const { allFoods, food } = options.context as FoodFormSchemaContext
const sameFoodExists = allFoods.some(({ name, id }) => {
const haveSameNames = currentName.toLowerCase() === name.toLowerCase()
return food ? id !== food.id && haveSameNames : haveSameNames
})
return !sameFoodExists
}
),
categoryId: number()
.notOneOf([0], 'Please select category')
.typeError('Please select category'),
energy: string().required('Please enter energy'),
servingSizeInGrams: string().required('Please enter a value'),
})
function useFoodForm(foodForm: FoodForm) {
const formMethods = useForm({
defaultValues: foodForm,
})
return formMethods
}
export type { FoodForm, FoodFormSchemaContext }
export {
useFoodForm,
getFoodForm,
foodFormSchema,
DEFAULT_SERVING_SIZE_IN_GRAMS,
}
================================================
FILE: src/foods/foodVolumeForm.ts
================================================
import { FoodVolume } from 'foods'
type FoodVolumeForm = {
portionId: string
weightInGrams: string
}
function getFoodVolumeForm(foodVolume?: FoodVolume): FoodVolumeForm {
if (foodVolume) {
return {
portionId: foodVolume.portionId,
weightInGrams: foodVolume.weightInGrams.toString(),
}
}
return {
portionId: 'milliliters',
weightInGrams: '',
}
}
export type { FoodVolumeForm }
export { getFoodVolumeForm }
================================================
FILE: src/foods/index.ts
================================================
export * from './foodForm'
export * from './useFoodsStore'
export { default as FoodInfo } from './FoodInfo'
export { default as FoodModal } from './FoodModal'
export * from './FoodModal'
export { default as FoodsList } from './FoodsList'
export * from './FoodsList'
export { default as FoodsDrawer } from './FoodsDrawer'
export * from './types'
export { default as builtInFoods } from './builtIn'
================================================
FILE: src/foods/persistence/FoodsListModal/Content.tsx
================================================
import {
ModalContent,
ModalHeader,
ModalCloseButton,
ModalFooter,
ModalBody,
Button,
HStack,
} from '@chakra-ui/react'
import { FoodsList, useFoods } from 'foods'
import { DownloadButton, getUntitledFileName } from 'persistence'
import { useState } from 'react'
type Action = 'import' | 'export'
type Props = {
onClose: () => void
title: string
onImport: () => void
action: Action
}
function Content({ onClose, title, onImport, action }: Props) {
const { allFoods } = useFoods()
const [blob] = useState(() => {
const allFoodsString = JSON.stringify(allFoods)
return new Blob([allFoodsString])
})
return (
{title}
{action === 'import' ? (
) : (
)}
)
}
export type { Props }
export default Content
================================================
FILE: src/foods/persistence/FoodsListModal/index.tsx
================================================
import { Modal, ModalOverlay, useToast } from '@chakra-ui/react'
import { Food, FoodsStoreProvider, useFoods, useFoodsActions } from 'foods'
import { DEFAULT_FILTER, FoodsFilterStoreProvider } from 'foods-filters'
import Content from './Content'
type Props = {
onClose: () => void
isOpen: boolean
foodsToImport?: Food[]
}
function FoodsListModal({ onClose, isOpen, foodsToImport }: Props) {
const title = foodsToImport ? 'Import Foods' : 'Export Foods'
const { userFoods } = useFoods()
const foodsActions = useFoodsActions()
const toast = useToast()
const foods = foodsToImport || userFoods
function onImport() {
if (foodsToImport) {
foodsActions.setFoods(foodsToImport)
toast({
position: 'top',
status: 'success',
title: 'Foods imported',
isClosable: true,
})
onClose()
}
}
return (
)
}
export type { Props }
export default FoodsListModal
================================================
FILE: src/foods/persistence/MissingFoodsModal.tsx
================================================
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Button,
Text,
} from '@chakra-ui/react'
type Props = {
isOpen: boolean
onClose: () => void
onImport: () => void
}
function MissingFoodsModal({ isOpen, onClose, onImport }: Props) {
return (
Missing foods
The meal plan you contains foods that are not part of your list.
You can try to import the missing foods or continue without them.
)
}
export default MissingFoodsModal
================================================
FILE: src/foods/persistence/index.ts
================================================
export { default as MissingFoodsModal } from './MissingFoodsModal'
export { default as useImportFoods } from './useImportFoods'
export { default as FoodsListModal } from './FoodsListModal'
export * from './FoodsListModal'
export { default as loadFoods } from './loadFoods'
================================================
FILE: src/foods/persistence/loadFoods.ts
================================================
import { builtInFoods } from 'foods'
function loadFoods() {
const userFoodsString = localStorage.getItem('userFoods')
if (userFoodsString) {
const userFoods = JSON.parse(userFoodsString)
return [...userFoods, ...builtInFoods]
}
return builtInFoods
}
export default loadFoods
================================================
FILE: src/foods/persistence/useImportFoods.ts
================================================
import { UseDisclosureReturn } from '@chakra-ui/hooks'
import { Food } from 'foods'
import { selectFile, readFile, useFileImportError } from 'persistence'
import { useState } from 'react'
type Params = {
foodsListModalDisclosure: UseDisclosureReturn
}
function useImportFoods({ foodsListModalDisclosure }: Params) {
const fileImportError = useFileImportError()
const [foodsToImport, setFoodsToImport] = useState()
async function onImport() {
const file = await selectFile('text/json')
try {
const text = await readFile(file)
const foodsToImport = JSON.parse(text) as Food[]
setFoodsToImport(foodsToImport)
foodsListModalDisclosure.onOpen()
} catch (error: any) {
fileImportError.onError({ error, file })
}
}
return {
onImport,
foodsToImport,
}
}
export default useImportFoods
================================================
FILE: src/foods/types.ts
================================================
import { NutritionData } from 'stats'
type FoodId = string | number
type FoodVolume = {
portionId: string
weightInGrams: number
}
type Food = {
id: FoodId
categoryId: number
name: string
addedByUser?: boolean
servingSizeInGrams?: number
volume?: FoodVolume
url?: string
} & NutritionData
export type { Food, FoodId, FoodVolume }
================================================
FILE: src/foods/useFoodsStore.ts
================================================
import { Food, FoodId } from 'foods'
import { useState, useCallback, useMemo } from 'react'
import produce from 'immer'
import { makeStoreProvider, useCallbacksMemo } from 'general'
import { useSaveValue } from 'persistence'
type Params = {
initialFoods: Food[]
}
function sortedFoods(foods: Food[]) {
return [...foods].sort((food1, food2) => {
if (food1.categoryId === food2.categoryId) {
return food1.name.localeCompare(food2.name)
}
return food1.categoryId - food2.categoryId
})
}
function useFoodsStore({ initialFoods }: Params) {
const [foodsById, setFoodsById] = useState>(() => {
const initialMap: Record = {}
for (const food of initialFoods) {
initialMap[food.id] = food
}
return initialMap
})
const setFoods = useCallback(
(foods: Food[]) =>
setFoodsById(
produce(draftFoodsById => {
for (const food of foods) {
draftFoodsById[food.id] = food
}
})
),
[]
)
const removeFood = useCallback(
(foodId: FoodId) =>
setFoodsById(
produce(draftFoodsById => {
delete draftFoodsById[foodId]
})
),
[]
)
const allFoods = useMemo(() => sortedFoods(Object.values(foodsById)), [
foodsById,
])
const userFoods = useMemo(
() => sortedFoods(allFoods.filter(food => food.addedByUser)),
[allFoods]
)
useSaveValue({ value: userFoods, key: 'userFoods' })
const actions = useCallbacksMemo({ setFoods, removeFood })
const state = useCallbacksMemo({
allFoods,
userFoods,
foodsById,
})
return [state, actions] as const
}
const [FoodsStoreProvider, useFoods, useFoodsActions] = makeStoreProvider(
useFoodsStore
)
export { FoodsStoreProvider, useFoods, useFoodsActions }
export default useFoodsStore
================================================
FILE: src/foods-categories/FoodCategoriesSelect.tsx
================================================
import { SelectProps, Select } from '@chakra-ui/select'
import foodCategories from './categories.json'
import { ForwardedRef, forwardRef } from 'react'
type Props = { forwardedRef?: ForwardedRef } & SelectProps
function FoodCategoriesSelect({ children, forwardedRef, ...rest }: Props) {
return (
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/foods-categories/categories.json
================================================
[
{ "name": "Poultry", "id": 100 },
{ "name": "Beef", "id": 200 },
{ "name": "Pork", "id": 300 },
{ "name": "Finfish & Shellfish", "id": 400 },
{ "name": "Dairy and eggs", "id": 500},
{ "name": "Grains & Pasta", "id": 600},
{ "name": "Vegetables", "id": 700 },
{ "name": "Legumes & Legume Products", "id": 800 },
{ "name": "Fruits & Juices", "id": 900 },
{ "name": "Nut and Seed Products", "id": 1000 },
{ "name": "Fats & Oils", "id": 2000 },
{ "name": "Baked Products", "id": 3000 },
{ "name": "Sauces & Soups", "id": 4000 },
{ "name": "Spices & Herbs", "id": 5000 },
{ "name": "Sweets & Snacks", "id": 6000 },
{ "name": "Beverages", "id": 7000 },
{ "name": "Other", "id": 8000 }
]
================================================
FILE: src/foods-categories/index.ts
================================================
export { default as FoodCategoriesSelect } from './FoodCategoriesSelect'
export * from './types'
export { default as foodCategories } from './categories.json'
================================================
FILE: src/foods-categories/types.ts
================================================
type FoodCategory = {
id: number
name: string
color: string
}
export type { FoodCategory }
================================================
FILE: src/foods-filters/FoodsFilterPopoverOrModal/Content.tsx
================================================
import { VStack, Checkbox } from '@chakra-ui/react'
import { FoodCategoriesSelect } from 'foods-categories'
import { useFoodsFilter, useFoodsFilterActions } from 'foods-filters'
import { ChangeEvent, RefObject } from 'react'
type Props = {
selectRef: RefObject
}
function Content({ selectRef }: Props) {
const filter = useFoodsFilter()
const foodsFilterActions = useFoodsFilterActions()
function onSelectChange(event: ChangeEvent) {
const { value } = event.target
foodsFilterActions.updateFilter({ categoryId: Number(value) })
}
function onCheckboxChange(event: ChangeEvent) {
const { checked } = event.target
foodsFilterActions.updateFilter({ onlyFoodsAddedByUser: checked })
}
return (
Only items added by me
)
}
export default Content
================================================
FILE: src/foods-filters/FoodsFilterPopoverOrModal/Footer.tsx
================================================
import { HStack, Button } from '@chakra-ui/react'
import {
nonQueryChangesCount,
useFoodsFilter,
useFoodsFilterActions,
} from 'foods-filters'
type Props = {
onClose: () => void
}
function Footer({ onClose }: Props) {
const filter = useFoodsFilter()
const foodsFilterActions = useFoodsFilterActions()
const changesCount = nonQueryChangesCount(filter)
function onReset() {
foodsFilterActions.resetFilter()
onClose()
}
return (
)
}
export default Footer
================================================
FILE: src/foods-filters/FoodsFilterPopoverOrModal/Modal.tsx
================================================
import {
Modal as ModalBase,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
} from '@chakra-ui/react'
import { useRef } from 'react'
import Content from './Content'
import Footer from './Footer'
type Props = {
isOpen: boolean
onClose: () => void
}
function Modal({ isOpen, onClose }: Props) {
const selectRef = useRef(null)
return (
Filters
)
}
export default Modal
================================================
FILE: src/foods-filters/FoodsFilterPopoverOrModal/Popover.tsx
================================================
import {
Popover as PopoverBase,
PopoverTrigger,
PopoverContent,
PopoverHeader,
PopoverBody,
PopoverFooter,
PopoverArrow,
PopoverCloseButton,
} from '@chakra-ui/react'
import { useRef } from 'react'
import Content from './Content'
import Trigger from './Trigger'
import Footer from './Footer'
function Popover() {
const selectRef = useRef(null)
return (
{({ onClose }) => {
return (
<>
Filters
>
)
}}
)
}
export default Popover
================================================
FILE: src/foods-filters/FoodsFilterPopoverOrModal/Trigger.tsx
================================================
import { Badge } from 'general'
import { IconButton } from '@chakra-ui/react'
import { Filter } from 'react-feather'
import { nonQueryChangesCount, useFoodsFilter } from 'foods-filters'
import { ForwardedRef, forwardRef } from 'react'
type Props = {
onClick?: () => void
forwardedRef?: ForwardedRef
}
function Trigger({ onClick, forwardedRef }: Props) {
const filter = useFoodsFilter()
const changesCount = nonQueryChangesCount(filter)
return (
}
variant="outline"
onClick={onClick}
/>
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/foods-filters/FoodsFilterPopoverOrModal/index.tsx
================================================
import { useScreenSize, ScreenSize } from 'general'
import Modal from './Modal'
import Trigger from './Trigger'
import Popover from './Popover'
import { useDisclosure } from '@chakra-ui/hooks'
function FoodsFilterPopoverOrModal() {
const screenSize = useScreenSize()
const modalDisclosure = useDisclosure()
if (screenSize < ScreenSize.Medium) {
return (
<>
>
)
}
return
}
export default FoodsFilterPopoverOrModal
================================================
FILE: src/foods-filters/foodsFilter.ts
================================================
const DEFAULT_FILTER: FoodsFilter = {
query: '',
onlyFoodsAddedByUser: false,
categoryId: 0,
}
type FoodsFilter = {
categoryId?: number
onlyFoodsAddedByUser?: boolean
query: string
}
function nonQueryChangesCount(filter: FoodsFilter) {
let count = 0
const { categoryId, onlyFoodsAddedByUser } = filter
if (categoryId !== DEFAULT_FILTER.categoryId) {
count++
}
if (onlyFoodsAddedByUser !== DEFAULT_FILTER.onlyFoodsAddedByUser) {
count++
}
return count
}
export type { FoodsFilter }
export { nonQueryChangesCount, DEFAULT_FILTER }
================================================
FILE: src/foods-filters/index.ts
================================================
export { default as useFilterFoods } from './useFilterFoods'
export * from './foodsFilter'
export { default as useFoodsFilterStore } from './useFoodsFilterStore'
export * from './useFoodsFilterStore'
export { default as FoodsFilterPopoverOrModal } from './FoodsFilterPopoverOrModal'
================================================
FILE: src/foods-filters/persistence/index.ts
================================================
export { default as loadFoodsFilter } from './loadFoodsFilter'
================================================
FILE: src/foods-filters/persistence/loadFoodsFilter.ts
================================================
import { DEFAULT_FILTER, FoodsFilter } from 'foods-filters'
function loadFoodsFilter() {
const foodsFilterString = localStorage.getItem('foodsFilter')
if (foodsFilterString) {
const foodsFilter = JSON.parse(foodsFilterString) as FoodsFilter
return foodsFilter
}
return DEFAULT_FILTER
}
export default loadFoodsFilter
================================================
FILE: src/foods-filters/useFilterFoods.ts
================================================
import Fuse from 'fuse.js'
import { useMemo } from 'react'
import { Food } from 'foods'
import { FoodsFilter } from './foodsFilter'
const OPTIONS = { keys: ['name'] }
function groupFoodsByCategoryId(foods: Food[]) {
const foodsByCategoryIdMap: Record = {}
for (const food of foods) {
const { categoryId } = food
if (!foodsByCategoryIdMap[categoryId]) {
foodsByCategoryIdMap[categoryId] = []
}
foodsByCategoryIdMap[categoryId].push(food)
}
return foodsByCategoryIdMap
}
function useFilterFoods(
allFoods: Food[],
userFoods: Food[],
filter: FoodsFilter
) {
const foodsToFilter = filter.onlyFoodsAddedByUser ? userFoods : allFoods
const fuse = useMemo(() => new Fuse(foodsToFilter, OPTIONS), [foodsToFilter])
const foodsByCategoryId = useMemo(
() => groupFoodsByCategoryId(foodsToFilter),
[foodsToFilter]
)
const { query, categoryId } = filter
if (!query) {
return categoryId ? foodsByCategoryId[categoryId] || [] : foodsToFilter
}
const foodsForQuery = fuse.search(query, { limit: 5 }).map(({ item }) => item)
if (!categoryId) {
return foodsForQuery
}
return foodsForQuery.filter(food => food.categoryId === categoryId)
}
export type { FoodsFilter }
export default useFilterFoods
================================================
FILE: src/foods-filters/useFoodsFilterStore.ts
================================================
import { useCallback, useState } from 'react'
import { FoodsFilter, DEFAULT_FILTER } from './foodsFilter'
import { makeStoreProvider, useCallbacksMemo } from 'general'
import { useSaveValue } from 'persistence'
type Params = {
initialFilter: FoodsFilter
shouldSaveFilter?: boolean
}
function filterWithoutQuery(filter: FoodsFilter) {
return { ...filter, query: '' }
}
function useFoodsFilterStore({
initialFilter,
shouldSaveFilter = true,
}: Params) {
const [filter, setFilter] = useState(initialFilter)
useSaveValue({
value: filterWithoutQuery(filter),
key: 'foodsFilter',
isEnabled: shouldSaveFilter,
})
const updateFilter = useCallback(
(partialFilter: Partial) =>
setFilter(filter => {
return { ...filter, ...partialFilter }
}),
[]
)
const resetFilter = useCallback(() => {
setFilter({ ...DEFAULT_FILTER })
}, [])
const resetCategoryIdAndQuery = useCallback(() => {
setFilter(filter => ({
...DEFAULT_FILTER,
onlyFoodsAddedByUser: filter.onlyFoodsAddedByUser,
}))
}, [])
const actions = useCallbacksMemo({
updateFilter,
resetFilter,
resetCategoryIdAndQuery,
})
return [filter, actions] as const
}
const [
FoodsFilterStoreProvider,
useFoodsFilter,
useFoodsFilterActions,
] = makeStoreProvider(useFoodsFilterStore)
export { FoodsFilterStoreProvider, useFoodsFilter, useFoodsFilterActions }
export default useFoodsFilterStore
================================================
FILE: src/form/duplicate.ts
================================================
import { deepCopy } from 'general'
import { v4 as uuidv4 } from 'uuid'
import { Form } from './types'
function duplicate(originalForm: T) {
const copiedForm = deepCopy(originalForm, (key: string, value: any) => {
if (key === 'fieldId') {
return uuidv4()
}
return value
}) as T
return copiedForm
}
export default duplicate
================================================
FILE: src/form/index.ts
================================================
export { default as duplicate } from './duplicate'
export * from './names'
export { default as useFormError } from './useFormError'
export { default as useSelectInputText } from './useSelectInputText'
================================================
FILE: src/form/names.ts
================================================
import { Form } from './types'
function getDuplicatedName(index: number, forms: Form[]) {
const form = forms[index]
const originalNameOrUntitled = form.name || 'Untitled'
return getEnumeratedName(`Copy of ${originalNameOrUntitled}`, forms)
}
function getEnumeratedName(currentName: string, forms: Form[]) {
const presentCount = forms.filter(({ name }) => name === currentName).length
if (presentCount > 0) {
return `${currentName} (${presentCount})`
}
return currentName
}
export { getDuplicatedName, getEnumeratedName }
================================================
FILE: src/form/types.ts
================================================
type Form = {
fieldId: string
name: string
}
export type { Form }
================================================
FILE: src/form/useFormError.ts
================================================
import { useFormContext } from 'react-hook-form'
function useFormError(name: string) {
const { formState } = useFormContext()
const { errors, touchedFields } = formState
const isInvalid =
errors[name] && (touchedFields[name] || formState.isSubmitted)
const errorMessage = isInvalid ? errors[name]?.message : undefined
return {
isInvalid,
errorMessage,
}
}
export default useFormError
================================================
FILE: src/form/useSelectInputText.ts
================================================
import { RefObject, useEffect } from 'react'
function useSelectInputText(inputRef: RefObject) {
useEffect(() => {
const input = inputRef.current
if (input) {
input.setSelectionRange(0, input.value.length)
}
}, [inputRef])
}
export default useSelectInputText
================================================
FILE: src/general/Badge.tsx
================================================
import { ForwardedRef, ReactNode } from 'react'
import { Box, BoxProps, Center, Fade, Text } from '@chakra-ui/react'
import { forwardRef } from 'react'
import { useSameOrPreviousValue } from 'general'
type Props = {
children: ReactNode
count: number
forwardedRef?: ForwardedRef
} & BoxProps
function Badge({ children, count, forwardedRef, ...rest }: Props) {
const prevCount = useSameOrPreviousValue(count)
return (
{children}
0}>
{count === 0 ? prevCount : count}
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/general/ContextMenuFlex.tsx
================================================
import { Flex, FlexProps } from '@chakra-ui/react'
import { ForwardedRef, ReactElement, forwardRef } from 'react'
import { MenuItem, ControlledMenu } from 'general'
import { useState } from 'react'
import { getMenuItems } from './MenuOrDrawer'
import { isDesktop } from 'react-device-detect'
type Props = {
menuItems?: ReactElement[]
menuOrDrawerItems?: ReactElement[]
forwardedRef?: ForwardedRef
} & FlexProps
function ContextMenuFlex({
menuItems,
menuOrDrawerItems = [],
children,
forwardedRef,
...rest
}: Props) {
const [isOpen, setOpen] = useState(false)
const [anchorPoint, setAnchorPoint] = useState({ x: 0, y: 0 })
return (
{
const { target, clientX, clientY } = event
if (
!isDesktop ||
(target as HTMLElement).tagName?.toLowerCase() === 'input'
) {
return
}
event.preventDefault()
setAnchorPoint({ x: clientX, y: clientY })
setOpen(true)
}}
>
{isDesktop && (
setOpen(false)}
>
{getMenuItems(menuOrDrawerItems)}
)}
{children}
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/general/HFadeScroll/FadeBox.tsx
================================================
import { ReactNode } from 'react'
import { Box } from '@chakra-ui/react'
type ShadowProps = {
hasStartFade: boolean
hasEndFade: boolean
children: ReactNode
}
function getLinearGradient(direction: 'left' | 'right') {
return `linear-gradient(to ${direction},#F7FAFC, rgba(255, 255, 255, 0))`
}
const shadowElementBase = {
content: '""',
position: 'absolute',
top: 0,
bottom: 0,
width: '50px',
zIndex: 1,
}
function FadeBox({ hasStartFade, hasEndFade, children }: ShadowProps) {
const before = {
...shadowElementBase,
left: 0,
background: getLinearGradient('right'),
}
const after = {
...shadowElementBase,
right: 0,
background: getLinearGradient('left'),
}
return (
{children}
)
}
export default FadeBox
================================================
FILE: src/general/HFadeScroll/ScrollContainer.tsx
================================================
import { Flex } from '@chakra-ui/react'
import styled from '@emotion/styled'
const ScrollContainer = styled(Flex)`
-ms-overflow-style: none;
scrollbar-width: none;
::-webkit-scrollbar {
display: none;
}
`
export default ScrollContainer
================================================
FILE: src/general/HFadeScroll/index.tsx
================================================
import {
ForwardedRef,
ReactNode,
forwardRef,
useRef,
useEffect,
useState,
} from 'react'
import ScrollContainer from './ScrollContainer'
import FadeBox from './FadeBox'
import { useMergeRefs } from '@chakra-ui/hooks'
type Props = {
children: ReactNode
forwardedRef?: ForwardedRef
onScrollStateChange: (
isScrollable: boolean,
canScrollLeft: boolean,
canScrollRight: boolean
) => void
}
const HFadeScroll = ({
children,
forwardedRef,
onScrollStateChange,
}: Props) => {
const [hasStartFade, setHasStartFade] = useState(false)
const [hasEndFade, setHasEndFade] = useState(false)
const scrollContainerRef = useRef(null)
const timeoutRef = useRef()
function onMousewheel(event: WheelEvent) {
const { deltaX } = event
if ((deltaX < 0 && !hasStartFade) || (deltaX > 0 && !hasEndFade)) {
event.preventDefault()
}
}
function onScroll() {
if (scrollContainerRef.current) {
const {
scrollWidth,
scrollLeft,
offsetWidth,
} = scrollContainerRef.current
setHasStartFade(scrollLeft > 0)
setHasEndFade(scrollLeft + offsetWidth + 1 < scrollWidth)
}
}
useEffect(() => {
onScroll()
window.clearTimeout(timeoutRef.current)
timeoutRef.current = window.setTimeout(onScroll, 300)
const scrollContainerNode = scrollContainerRef.current
scrollContainerNode?.addEventListener('scroll', onScroll)
scrollContainerNode?.addEventListener('wheel', onMousewheel)
window.addEventListener('resize', onScroll)
return () => {
window.removeEventListener('resize', onScroll)
scrollContainerNode?.removeEventListener('scroll', onScroll)
scrollContainerNode?.removeEventListener('wheel', onMousewheel)
window.clearTimeout(timeoutRef.current)
}
})
useEffect(() => {
if (scrollContainerRef.current) {
const { scrollWidth, offsetWidth } = scrollContainerRef.current
onScrollStateChange(offsetWidth < scrollWidth, hasStartFade, hasEndFade)
}
})
const finalScrollContainerRef = useMergeRefs(scrollContainerRef, forwardedRef)
return (
{children}
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/general/Loader.tsx
================================================
import { Spinner, Text, Center, Flex } from '@chakra-ui/react'
type Props = {
label: string
}
function Loader({ label }: Props) {
return (
{label}
)
}
export default Loader
================================================
FILE: src/general/Menu.tsx
================================================
import styled from '@emotion/styled'
import {
Menu as MenuBase,
MenuButton,
MenuItem,
ControlledMenu as ControlledMenuBase,
MenuDivider,
MenuHeader,
} from '@szhsin/react-menu'
import '@szhsin/react-menu/dist/index.css'
const bowShadow =
'box-shadow: 0 3px 7px rgb(0 0 0 / 13%), 0 0.6px 2px rgb(0 0 0 / 10%) !important'
const Menu = styled(MenuBase)`
${bowShadow}
`
const ControlledMenu = styled(ControlledMenuBase)`
${bowShadow}
`
export { MenuButton, MenuItem, ControlledMenu, MenuDivider, MenuHeader }
export default Menu
================================================
FILE: src/general/MenuOrDrawer/Drawer/getDrawerButtons.tsx
================================================
import { cloneElement, ReactElement, Children } from 'react'
import { Button, Divider } from '@chakra-ui/react'
import MenuOrDrawerItem from '../MenuOrDrawerItem'
import MenuOrDrawerSeparator from '../MenuOrDrawerSeparator'
function getDrawerButtons(
children: ReactElement | ReactElement[],
onClose: () => void
) {
return Children.map(children, child => {
if (child.type === MenuOrDrawerItem) {
const icon = cloneElement(child.props.icon, {
size: 20,
})
return (
)
} else if (child.type === MenuOrDrawerSeparator) {
return
}
return null
})
}
export default getDrawerButtons
================================================
FILE: src/general/MenuOrDrawer/Drawer/index.tsx
================================================
import {
Drawer as DrawerBase,
DrawerBody,
DrawerHeader,
DrawerOverlay,
DrawerContent,
DrawerCloseButton,
VStack,
} from '@chakra-ui/react'
import { ReactElement } from 'react'
import getDrawerButtons from './getDrawerButtons'
type Props = {
isOpen: boolean
onClose: () => void
children: ReactElement | ReactElement[]
title: string
}
function Drawer({ title, isOpen, onClose, children }: Props) {
return (
{title}
{getDrawerButtons(children, onClose)}
)
}
export { getDrawerButtons }
export default Drawer
================================================
FILE: src/general/MenuOrDrawer/Menu/getMenuItems.tsx
================================================
import {
MenuItem,
MenuOrDrawerItem,
MenuOrDrawerSeparator,
MenuDivider,
} from 'general'
import { cloneElement, ReactElement, Children } from 'react'
function getMenuItems(children: ReactElement | ReactElement[]) {
return Children.map(children, (child: ReactElement) => {
if (child.type === MenuOrDrawerItem) {
const icon = cloneElement(child.props.icon, { size: 16, mr: 3 })
return (
)
} else if (child.type === MenuOrDrawerSeparator) {
return
}
return null
})
}
export default getMenuItems
================================================
FILE: src/general/MenuOrDrawer/Menu/index.tsx
================================================
import { ButtonProps } from '@chakra-ui/react'
import { Menu as MenuBase, MenuHeader } from 'general'
import Trigger from '../Trigger'
import { ReactElement } from 'react'
import getMenuItems from './getMenuItems'
type Props = {
children: ReactElement | ReactElement[]
title: string
} & ButtonProps
function Menu({ children, title, ...rest }: Props) {
return (
}
>
{title}
{getMenuItems(children)}
)
}
export { getMenuItems }
export default Menu
================================================
FILE: src/general/MenuOrDrawer/MenuOrDrawerItem.tsx
================================================
import { ReactElement, ReactNode } from 'react'
type Props = {
onClick?: () => void
children: ReactNode
icon: ReactElement
isDisabled?: boolean
}
function MenuItem(props: Props) {
return null
}
export default MenuItem
================================================
FILE: src/general/MenuOrDrawer/MenuOrDrawerSeparator.tsx
================================================
function MenuOrDrawerSeparator() {
return null
}
export default MenuOrDrawerSeparator
================================================
FILE: src/general/MenuOrDrawer/Trigger.tsx
================================================
import { IconButton, ButtonProps } from '@chakra-ui/react'
import { MoreHorizontal } from 'react-feather'
import { ForwardedRef, forwardRef } from 'react'
type Props = {
forwardedRef?: ForwardedRef
} & ButtonProps
function Trigger({ forwardedRef, ...rest }: Props) {
return (
}
variant="ghost"
size="sm"
ref={forwardedRef}
{...rest}
/>
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/general/MenuOrDrawer/index.tsx
================================================
import { useScreenSize, ScreenSize } from 'general'
import Drawer from './Drawer'
import Trigger from './Trigger'
import { useDisclosure, IconButtonProps } from '@chakra-ui/react'
import Menu from './Menu'
import { ReactElement } from 'react'
type Props = {
children: ReactElement | ReactElement[]
title: string
} & IconButtonProps
function MenuOrDrawer({ children, title, ...rest }: Props) {
const screenSize = useScreenSize()
const modalDisclosure = useDisclosure()
if (screenSize < ScreenSize.Medium) {
return (
<>
{children}
>
)
}
return (
)
}
export { default as MenuOrDrawerItem } from './MenuOrDrawerItem'
export { default as MenuOrDrawerSeparator } from './MenuOrDrawerSeparator'
export * from './Menu'
export * from './Drawer'
export default MenuOrDrawer
================================================
FILE: src/general/ResponsiveButton.tsx
================================================
import { Button, ButtonProps } from '@chakra-ui/react'
import { useScreenSize, ScreenSize } from 'general'
import { ForwardedRef, forwardRef } from 'react'
type Props = {
forwardedRef?: ForwardedRef
} & ButtonProps
function ResponsiveButton({ forwardedRef, ...rest }: Props) {
const screenSize = useScreenSize()
const size = screenSize >= ScreenSize.Medium ? 'sm' : 'sm'
return
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/general/ResponsiveIconButton.tsx
================================================
import { IconButtonProps, IconButton } from '@chakra-ui/react'
import { useScreenSize, ScreenSize } from 'general'
import { ForwardedRef, forwardRef } from 'react'
type Props = {
forwardedRef?: ForwardedRef
tooltip?: string
} & IconButtonProps
function ResponsiveIconButton({
forwardedRef,
...rest
}: Props) {
const screenSize = useScreenSize()
const size = screenSize >= ScreenSize.Medium ? 'sm' : 'sm'
return
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/general/RightAligned.tsx
================================================
import { Flex, FlexProps } from '@chakra-ui/react'
import { ReactNode } from 'react'
type Props = {
children: ReactNode
} & FlexProps
function RightAligned({ children, ...rest }: Props) {
return (
{children}
)
}
export default RightAligned
================================================
FILE: src/general/ScreenSizeProvider/context.ts
================================================
import { createContext, useContext } from 'react'
enum ScreenSize {
Base = 0,
Small,
Medium,
Large,
ExtraLarge,
}
const ScreenSizeContext = createContext(undefined)
function useScreenSize() {
const screenSize = useContext(ScreenSizeContext)
if (screenSize === undefined) {
throw new Error('Provider missing')
}
return screenSize
}
export { useScreenSize, ScreenSizeContext, ScreenSize }
================================================
FILE: src/general/ScreenSizeProvider/index.tsx
================================================
import { useBreakpointValue } from '@chakra-ui/media-query'
import { ReactNode } from 'react'
import { ScreenSizeContext, ScreenSize } from './context'
type Props = {
children: ReactNode
}
function ScreenSizeProvider({ children }: Props) {
const screenSize = useBreakpointValue({
base: ScreenSize.Base,
sm: ScreenSize.Small,
md: ScreenSize.Medium,
lg: ScreenSize.Large,
xl: ScreenSize.ExtraLarge,
})
if (screenSize === undefined) {
return null
}
return (
{children}
)
}
export * from './context'
export default ScreenSizeProvider
================================================
FILE: src/general/Tooltip.tsx
================================================
import { ReactElement, useState, cloneElement, useRef, ReactNode } from 'react'
import { Tooltip as TooltipBase } from '@chakra-ui/react'
type Props = {
children: ReactElement
delay?: number
label?: ReactNode
isActive?: boolean
}
function Tooltip({ children, label, isActive = true, delay = 500 }: Props) {
const [isHovered, setIsHovered] = useState(false)
const timeoutIdRef = useRef()
function onMouseEnter() {
window.clearTimeout(timeoutIdRef.current)
timeoutIdRef.current = window.setTimeout(() => setIsHovered(true), delay)
}
function hideTooltip() {
window.clearTimeout(timeoutIdRef.current)
setIsHovered(false)
}
function onMouseLeave() {
hideTooltip()
}
function onClick(...rest: any) {
children.props.onClick && children.props.onClick(...rest)
hideTooltip()
}
if (!isActive) {
return children
}
return (
{cloneElement(children, {
onMouseEnter,
onMouseLeave,
onClick,
})}
)
}
export default Tooltip
================================================
FILE: src/general/TooltipCommandLabel.tsx
================================================
import { Text } from '@chakra-ui/react'
type Props = {
command: string
kbdCombo: string
}
function TooltipCommandLabel({ command, kbdCombo }: Props) {
return (
{command}{' '}
{kbdCombo}
)
}
export default TooltipCommandLabel
================================================
FILE: src/general/deepCopy.ts
================================================
const deepCopy = (value: any, replacer?: (key: string, value: any) => any) =>
JSON.parse(JSON.stringify(value, replacer))
export default deepCopy
================================================
FILE: src/general/getCtrlKeyName.ts
================================================
function isMac() {
return navigator.platform.indexOf('Mac') > -1
}
function getCtrlKeyName() {
if (isMac()) {
return 'Cmd'
}
return 'Ctrl'
}
export default getCtrlKeyName
================================================
FILE: src/general/index.ts
================================================
export { default as HFadeScroll } from './HFadeScroll'
export * from './HFadeScroll'
export { default as Badge } from './Badge'
export { default as deepCopy } from './deepCopy'
export { default as Menu } from './Menu'
export * from './Menu'
export { default as ResponsiveButton } from './ResponsiveButton'
export { default as ResponsiveIconButton } from './ResponsiveIconButton'
export { default as RightAligned } from './RightAligned'
export * from './stores'
export { default as useSelection } from './useSelection'
export * from './useSelection'
export { default as useSameOrPreviousValue } from './useSameOrPreviousValue'
export { default as ContextMenuFlex } from './ContextMenuFlex'
export { default as Loader } from './Loader'
export { default as useElementHeight } from './useElementHeight'
export { default as Tooltip } from './Tooltip'
export { default as getCtrlKeyName } from './getCtrlKeyName'
export { default as TooltipCommandLabel } from './TooltipCommandLabel'
export { default as ScreenSizeProvider } from './ScreenSizeProvider'
export * from './ScreenSizeProvider'
export * from './useOneTimeCheckStore'
export { default as MenuOrDrawer } from './MenuOrDrawer'
export * from './MenuOrDrawer'
export { default as minDelay } from './minDelay'
export { default as useRunIfNotUnmounted } from './useRunIfNotUnmounted'
================================================
FILE: src/general/minDelay.ts
================================================
function minDelay(startDate: Date, minDelayInMs = 500) {
return new Promise(resolve => {
const endDate = new Date()
const timeDiffInMs = endDate.getTime() - startDate.getTime()
if (timeDiffInMs >= minDelayInMs) {
resolve(true)
} else {
setTimeout(() => resolve(true), minDelayInMs - timeDiffInMs)
}
})
}
export default minDelay
================================================
FILE: src/general/stores.tsx
================================================
import {
Context,
useContext,
createContext,
ReactNode,
useMemo,
Provider,
} from 'react'
function guard(value: unknown): value is object {
return value !== undefined
}
function makeUseContext(context: Context) {
function useCustomContext() {
const value = useContext(context)
if (!guard(value)) {
throw new Error('Missing store context provider')
}
return value
}
return useCustomContext
}
function makeProvider() {
const Context = createContext(undefined)
const useContext = makeUseContext(Context)
return [Context.Provider, useContext] as const
}
function makeStoreProvider(
useStore: (params: StoreParams) => readonly [State, Actions],
...selectors: ((state: State) => any)[]
) {
const [StateProvider, useState] = makeProvider()
const [ActionsProvider, useActions] = makeProvider()
const selectorProviders: Provider[] = []
const useSelectorHooks: any[] = []
selectors.forEach(() => {
const [SelectorProvider, useSelector] = makeProvider()
selectorProviders.push(SelectorProvider)
useSelectorHooks.push(useSelector)
})
function StoreProvider(props: StoreParams & { children: ReactNode }) {
const { children, ...storeParams } = props
const [state, methods] = useStore(storeParams as StoreParams)
let finalChildren = children
selectorProviders.forEach((SelectorProvider, index) => {
const selector = selectors[index]
const value = selector(state)
finalChildren = (
{finalChildren}
)
})
return (
{finalChildren}
)
}
return [StoreProvider, useState, useActions, ...useSelectorHooks] as const
}
function useCallbacksMemo(methods: T) {
return useMemo(() => methods, Object.values(methods)) // eslint-disable-line react-hooks/exhaustive-deps
}
export { makeStoreProvider, useCallbacksMemo }
================================================
FILE: src/general/useElementHeight.ts
================================================
import { useRef, useState } from 'react'
import useResizeObserver from '@react-hook/resize-observer'
function useElementHeight() {
const elementRef = useRef(null)
const [elementHeight, setElementHeight] = useState(0)
useResizeObserver(elementRef, entry =>
setElementHeight(entry.contentRect.height)
)
return {
elementRef,
elementHeight,
}
}
export default useElementHeight
================================================
FILE: src/general/useOneTimeCheckStore.ts
================================================
import { makeStoreProvider, useCallbacksMemo } from 'general'
import { useRef, useCallback } from 'react'
type KeysMap = {
[key: string]: boolean | undefined
}
function useOneTimeCheckStore() {
const keysMapRef = useRef({})
const checkAndReset = useCallback((key: string) => {
if (keysMapRef.current[key] === true) {
setTimeout(() => {
keysMapRef.current[key] = undefined
}, 0)
return true
}
return false
}, [])
const set = useCallback((key: string) => {
keysMapRef.current[key] = true
}, [])
const actions = useCallbacksMemo({
checkAndReset,
set,
})
return [keysMapRef, actions] as const
}
const [
OneTimeCheckStoreProvider,
useOneTimeCheck,
useOneTimeCheckActions,
] = makeStoreProvider(useOneTimeCheckStore)
type OneTimeCheckActions = ReturnType
export { OneTimeCheckStoreProvider, useOneTimeCheck, useOneTimeCheckActions }
export type { OneTimeCheckActions }
export default useOneTimeCheckStore
================================================
FILE: src/general/useRunIfNotUnmounted.ts
================================================
import { useCallback, useEffect, useRef } from 'react'
function useRunIfNotUnmounted() {
const isUnmountedRef = useRef(false)
useEffect(() => {
return () => {
isUnmountedRef.current = true
}
}, [])
const callIfNotUnmounted = useCallback((callback: Function) => {
if (!isUnmountedRef.current) {
callback()
}
}, [])
return callIfNotUnmounted
}
export default useRunIfNotUnmounted
================================================
FILE: src/general/useSameOrPreviousValue.ts
================================================
import { useEffect, useRef } from 'react'
function useSameOrPreviousValue(value: T) {
const previous = useRef(value)
useEffect(() => {
previous.current = value
}, [value])
return previous.current
}
export default useSameOrPreviousValue
================================================
FILE: src/general/useSelection.ts
================================================
import { useState } from 'react'
type Id = number | string
type Item = { id: Id }
type SelectionMap = { [id in Id]: boolean | undefined }
type Selection = {
isIdSelected: (id: Id) => boolean
toggleItem: (item: T) => void
addItem: (item: T) => void
removeItem: (item: T) => void
selectedItems: T[]
selectionMap: SelectionMap
}
function useSelection(): Selection {
const [selectionMap, setSelectionMap] = useState({})
const [selectedItems, setSelectedItems] = useState([])
function toggleItem(item: T) {
const { id } = item
const isSelected = Boolean(selectionMap[id])
if (isSelected) {
removeItem(item)
} else {
addItem(item)
}
setSelectionMap({ ...selectionMap, [id]: !isSelected })
}
function removeItem(item: T) {
setSelectedItems(selectedItems.filter(({ id }) => item.id !== id))
}
function addItem(item: T) {
setSelectedItems([...selectedItems, item])
}
function isIdSelected(id: Id) {
const isSelected = Boolean(selectionMap[id])
return isSelected
}
return {
isIdSelected,
toggleItem,
selectionMap,
selectedItems,
removeItem,
addItem,
}
}
export type { Selection, Item }
export default useSelection
================================================
FILE: src/icons/CalendarPlus.tsx
================================================
import { chakra } from '@chakra-ui/react'
function CalendarPlus({ size = 24, ...rest }) {
return (
)
}
export default chakra(CalendarPlus)
================================================
FILE: src/icons/index.ts
================================================
export { default as CalendarPlus } from './CalendarPlus'
================================================
FILE: src/index.tsx
================================================
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import reportWebVitals from './reportWebVitals'
ReactDOM.render(
,
document.getElementById('root')
)
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals()
================================================
FILE: src/ingredients/IngredientsList/EmptyList.tsx
================================================
import { Flex, Text, Button } from '@chakra-ui/react'
type Props = {
onAddIngredients: () => void
}
function EmptyList({ onAddIngredients }: Props) {
return (
You haven't added any foods
)
}
export default EmptyList
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/MenuOrDrawer.tsx
================================================
import { RightAligned } from 'layout'
import { MenuOrDrawer as MenuOrDrawerBase } from 'general'
import { ReactElement } from 'react'
type Props = {
children: ReactElement[]
}
function MenuOrDrawer({ children }: Props) {
return (
{children}
)
}
export default MenuOrDrawer
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/MissingStatsLayout.tsx
================================================
import { Flex, Text, Button } from '@chakra-ui/react'
import { Trash2 } from 'react-feather'
type Props = {
onRemoveRequest: () => void
}
function MissingStatsLayout({ onRemoveRequest }: Props) {
return (
Food not found
}
>
Remove
)
}
export default MissingStatsLayout
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/Notes.tsx
================================================
import PresenceAnimation from './PresenceAnimation'
import { Box, Text } from '@chakra-ui/react'
import { NotesEvents } from './useNotesEvents'
import { IngredientForm } from 'ingredients'
type Props = {
notesEvents: NotesEvents
ingredientForm: IngredientForm
}
function Notes({ notesEvents, ingredientForm }: Props) {
return (
{ingredientForm.notes}
)
}
export default Notes
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/PresenceAnimation.tsx
================================================
import { ReactNode } from 'react'
import { motion } from 'framer-motion'
type Props = {
children: ReactNode
shouldAnimate: boolean
onAnimationComplete: () => void
isVisible: boolean
isDraggingOver?: boolean
}
const variants = {
open: {
opacity: 1,
height: 'auto',
},
collapsed: { opacity: 0, height: 0 },
}
function PresenceAnimation({
shouldAnimate,
onAnimationComplete,
isVisible,
children,
isDraggingOver = false,
}: Props) {
return (
{children}
)
}
export default PresenceAnimation
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/StatsLayout.tsx
================================================
import { IngredientForm } from 'ingredients'
import { Food, FoodInfo } from 'foods'
import { StatsLayout as StatsLayoutBase, Stat, AmountInput } from 'stats'
import { ChangeEvent, ReactElement, ReactNode } from 'react'
import { Portion, PortionsMenuOrDrawer } from 'portions'
import { Flex } from '@chakra-ui/react'
type Props = {
energy: number
protein: number
carbs: number
fat: number
ingredientForm: IngredientForm
onAmountChange: (event: ChangeEvent) => void
onPortionChange: (portion: Portion) => void
menuElement: ReactElement
food: Food
notes?: string
children: ReactNode
}
function StatsLayout({
energy,
protein,
carbs,
fat,
ingredientForm,
onAmountChange,
onPortionChange,
menuElement,
food,
notes,
children,
}: Props) {
const acceptsFractions = ['teaspoons', 'tablespoons', 'cups'].includes(
ingredientForm.portionId
)
return (
{children}
}
amountElement={
}
energyElement={}
proteinElement={}
carbsElement={}
fatElement={}
menuElement={menuElement}
/>
)
}
export default StatsLayout
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/getMenuOrDrawerItems.tsx
================================================
import { chakra } from '@chakra-ui/react'
import { IngredientForm } from 'ingredients'
import { Trash2, Info, Edit } from 'react-feather'
import { MenuOrDrawerItem, MenuOrDrawerSeparator } from 'general'
const InfoStyled = chakra(Info)
const Trash2Styled = chakra(Trash2)
const EditStyled = chakra(Edit)
type Props = {
onEditNotes: () => void
onRemove: () => void
onViewFoodDetails: () => void
ingredientForm: IngredientForm
}
function getMenuOrDrawerItems({
ingredientForm,
onRemove,
onViewFoodDetails,
onEditNotes,
}: Props) {
return [
}
onClick={onViewFoodDetails}
>
View details
,
,
}
onClick={onEditNotes}
>
{ingredientForm.notes ? 'Edit notes' : 'Add notes'}
,
} onClick={onRemove}>
Remove
,
]
}
export default getMenuOrDrawerItems
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/index.tsx
================================================
import { IngredientForm } from 'ingredients'
import { Draggable } from 'react-beautiful-dnd'
import { memo } from 'react'
import { FoodModal, useFoods } from 'foods'
import { ContextMenuFlex } from 'general'
import PresenceAnimation from './PresenceAnimation'
import useIngredientsEvents from './useIngredientsEvents'
import getMenuOrDrawerItems from './getMenuOrDrawerItems'
import StatsLayout from './StatsLayout'
import MissingStatsLayout from './MissingStatsLayout'
import { useDisclosure } from '@chakra-ui/react'
import { EditNotesModal } from 'notes'
import useNotesEvents from './useNotesEvents'
import Notes from './Notes'
import MenuOrDrawer from './MenuOrDrawer'
type Props = {
variantIndex: number
mealIndex: number
index: number
ingredientForm: IngredientForm
energy: number
protein: number
carbs: number
fat: number
onRemove: (variantIndex: number, mealIndex: number, index: number) => void
shouldAddRadiusToLastBottomBorder: boolean
isLast: boolean
isDraggingOver: boolean
}
function IngredientItem({
variantIndex,
mealIndex,
index,
ingredientForm,
energy,
protein,
carbs,
fat,
onRemove,
shouldAddRadiusToLastBottomBorder,
isLast,
isDraggingOver,
...rest
}: Props) {
const { foodsById } = useFoods()
const food = foodsById[ingredientForm.foodId]
const ingredientEvents = useIngredientsEvents({
variantIndex,
mealIndex,
index,
onRemove,
ingredientForm,
food,
})
const notesEvents = useNotesEvents({
variantIndex,
mealIndex,
index,
ingredientForm,
})
const foodModalDisclosure = useDisclosure()
const editNotesModalDisclosure = useDisclosure()
const menuOrDrawerItems = getMenuOrDrawerItems({
onEditNotes: editNotesModalDisclosure.onOpen,
onRemove: ingredientEvents.onRemoveRequest,
onViewFoodDetails: foodModalDisclosure.onOpen,
ingredientForm,
})
// console.log('ingredient', variantIndex, mealIndex, index)
return (
{(provided, { isDragging }) => (
{food ? (
{menuOrDrawerItems}}
food={food}
notes={ingredientForm.notes}
>
{ingredientForm.notes && (
)}
) : (
)}
{food && (
)}
{food && (
)}
)}
)
}
export default memo(IngredientItem)
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/useIngredientsEvents.ts
================================================
import { useDietFormActions } from 'diets'
import { useOneTimeCheckActions } from 'general'
import { ChangeEvent, useState } from 'react'
import {
getInsertIngredientFormAnimationKey,
IngredientForm,
} from 'ingredients'
import { useToast } from '@chakra-ui/toast'
import { Portion, formatAmount, useGetAmount } from 'portions'
import { Food } from 'foods'
import amountAsNumber from 'stats/amountAsNumber'
type Params = {
variantIndex: number
mealIndex: number
index: number
ingredientForm: IngredientForm
food: Food
onRemove: (variantIndex: number, mealIndex: number, index: number) => void
}
function useIngredientsEvents({
variantIndex,
mealIndex,
index,
onRemove,
ingredientForm,
food,
}: Params) {
const [isVisible, setIsVisible] = useState(true)
const dietFormActions = useDietFormActions()
const toast = useToast()
const { getAmountFromPortionToPortion } = useGetAmount()
const oneTimeCheckActions = useOneTimeCheckActions()
const shouldAnimate = oneTimeCheckActions.checkAndReset(
getInsertIngredientFormAnimationKey(ingredientForm.fieldId)
)
function onAmountChange(event: ChangeEvent) {
const { value } = event.target
dietFormActions.updateIngredientForm(variantIndex, mealIndex, index, {
amount: value,
})
}
function onPortionChange(newPortion: Portion) {
const newAmount = getAmountFromPortionToPortion(
amountAsNumber(ingredientForm.amount),
ingredientForm.portionId,
newPortion.id,
food
)
dietFormActions.updateIngredientForm(variantIndex, mealIndex, index, {
portionId: newPortion.id,
amount: formatAmount(newAmount, newPortion.id),
})
}
function onAnimationComplete() {
if (!isVisible) {
onRemove(variantIndex, mealIndex, index)
}
}
function onFoodUpdated() {
toast({
position: 'top',
title: 'Food updated',
status: 'success',
duration: 2000,
isClosable: true,
})
}
function onRemoveRequest() {
setIsVisible(false)
}
return {
onAmountChange,
onAnimationComplete,
onRemoveRequest,
isVisible,
shouldAnimate,
onFoodUpdated,
onPortionChange,
}
}
export default useIngredientsEvents
================================================
FILE: src/ingredients/IngredientsList/IngredientItem/useNotesEvents.tsx
================================================
import { useDietFormActions } from 'diets'
import { useOneTimeCheckActions } from 'general'
import { IngredientForm } from 'ingredients'
import { useRef, useState } from 'react'
type Params = {
variantIndex: number
mealIndex: number
index: number
ingredientForm: IngredientForm
}
function useNotesEvents({
variantIndex,
mealIndex,
index,
ingredientForm,
}: Params) {
const [areNotesVisible, setAreNotesVisible] = useState(true)
const dietFormActions = useDietFormActions()
const oneTimeCheckActions = useOneTimeCheckActions()
const ref = useRef()
const shouldAnimateNotes = oneTimeCheckActions.checkAndReset(
`notes-${ingredientForm.fieldId}`
)
function onEditNotes(notes?: string) {
if (ingredientForm.notes) {
ref.current = notes
setAreNotesVisible(false)
} else {
if (notes) {
dietFormActions.updateIngredientForm(variantIndex, mealIndex, index, {
notes,
})
}
setAreNotesVisible(Boolean(notes))
}
}
function onNotesAnimationComplete() {
if (!areNotesVisible) {
dietFormActions.updateIngredientForm(variantIndex, mealIndex, index, {
notes: ref.current,
})
ref.current = undefined
setAreNotesVisible(true)
}
}
return {
areNotesVisible,
shouldAnimateNotes,
onEditNotes,
onNotesAnimationComplete,
}
}
type NotesEvents = ReturnType
export type { NotesEvents }
export default useNotesEvents
================================================
FILE: src/ingredients/IngredientsList/index.tsx
================================================
import { Box, Fade } from '@chakra-ui/react'
import IngredientItem from './IngredientItem'
import { Droppable } from 'react-beautiful-dnd'
import EmptyList from './EmptyList'
import { useDietFormActions } from 'diets'
import { IngredientForm } from 'ingredients'
import { memo } from 'react'
import { Stats } from 'stats'
type Props = {
mealIndex: number
variantIndex: number
mealFormFieldId: string
onAddIngredients: () => void
ingredientsForms: IngredientForm[]
ingredientsStats: Stats[]
shouldAddRadiusToLastBottomBorder?: boolean
}
function IngredientsList({
variantIndex,
mealIndex,
mealFormFieldId,
onAddIngredients,
ingredientsForms,
ingredientsStats,
shouldAddRadiusToLastBottomBorder,
}: Props) {
const dietFormActions = useDietFormActions()
return (
{(provided, snapshot) => (
{ingredientsForms.map((ingredientForm, index) => {
const { energy, protein, carbs, fat } = ingredientsStats[index]
return (
)
})}
{ingredientsForms.length > 0 && provided.placeholder}
{ingredientsForms.length === 0 && (
)}
)}
)
}
export default memo(IngredientsList)
================================================
FILE: src/ingredients/PdfIngredientsList/PdfIngredientItem/FoodName.tsx
================================================
import { Text, StyleSheet, View, Link } from '@react-pdf/renderer'
import { Food, FoodId } from 'foods'
import { IngredientForm } from 'ingredients'
import { Portion } from 'portions'
import getComputedColorFromChakra from 'theme/getComputedColorFromChakra'
import getIngredientPortionDescription from 'portions/getIngredientPortionDescription'
type Props = {
ingredientForm: IngredientForm
foodsById: Record
portionsById: Record
}
function Name({ ingredientForm, foodsById, portionsById }: Props) {
const { foodId } = ingredientForm
const food = foodsById[foodId]
const text = (
<>
{getIngredientPortionDescription(
ingredientForm,
foodsById,
portionsById
)}
{' '}
{food.name}
>
)
return (
{food.url ? (
{text}
) : (
{text}
)}
{ingredientForm.notes && (
{ingredientForm.notes}
)}
)
}
const styles = StyleSheet.create({
root: { marginLeft: 12 },
nameText: {
fontSize: 14,
},
nameLink: {
fontSize: 14,
textDecoration: 'none',
},
notes: {
marginTop: 3,
fontSize: 12,
},
})
export default Name
================================================
FILE: src/ingredients/PdfIngredientsList/PdfIngredientItem/index.tsx
================================================
import { StyleSheet, View } from '@react-pdf/renderer'
import { Food, FoodId } from 'foods'
import { IngredientForm } from 'ingredients'
import { Portion } from 'portions'
import { Stats } from 'stats'
import PdfStat from 'stats/PdfStat'
import PdfStatsLayout from 'stats/PdfStatsLayout'
import FoodName from './FoodName'
type Props = {
ingredientForm: IngredientForm
stats: Stats
foodsById: Record
portionsById: Record
isLast: boolean
}
function PdfIngredientItem({
ingredientForm,
stats,
foodsById,
portionsById,
isLast,
}: Props) {
return (
}
energyElement={
}
proteinElement={}
carbsElement={}
fatElement={}
/>
)
}
const styles = StyleSheet.create({
root: { paddingTop: 12, paddingBottom: 12, backgroundColor: 'white' },
name: {
fontSize: 14,
},
})
export default PdfIngredientItem
================================================
FILE: src/ingredients/PdfIngredientsList/index.tsx
================================================
import { View, Text, StyleSheet } from '@react-pdf/renderer'
import { Food, FoodId } from 'foods'
import { IngredientForm } from 'ingredients'
import { Portion } from 'portions'
import { Stats } from 'stats'
import getComputedColorFromChakra from 'theme/getComputedColorFromChakra'
import PdfIngredientItem from './PdfIngredientItem'
type Props = {
ingredientsForms: IngredientForm[]
ingredientsFormsStats: Stats[]
foodsById: Record
portionsById: Record
}
function PdfIngredientsList({
ingredientsForms,
ingredientsFormsStats,
foodsById,
portionsById,
}: Props) {
const filteredIngredientsForms = ingredientsForms.filter(
({ foodId }) => foodsById[foodId]
)
return (
{filteredIngredientsForms.map((ingredientForm, index) => {
const stats = ingredientsFormsStats[index]
return (
)
})}
{ingredientsForms.length === 0 && (
You haven't added any foods
)}
)
}
const styles = StyleSheet.create({
emptyListText: {
backgroundColor: 'white',
padding: 12,
fontSize: 14,
borderBottomLeftRadius: 7,
borderBottomRightRadius: 7,
},
})
export default PdfIngredientsList
================================================
FILE: src/ingredients/getIngredient.ts
================================================
import { DEFAULT_SERVING_SIZE_IN_GRAMS, Food } from 'foods'
import { Ingredient } from './types'
function getIngredient(food: Food): Ingredient {
const { volume } = food
if (
volume &&
['tablespoons', 'teaspoons', 'cups'].includes(volume.portionId)
) {
const { portionId } = volume
return {
foodId: food.id,
amount: 1,
portionId,
}
}
return {
foodId: food.id,
amount: food.servingSizeInGrams || DEFAULT_SERVING_SIZE_IN_GRAMS,
portionId: 'grams',
}
}
export default getIngredient
================================================
FILE: src/ingredients/index.ts
================================================
export { default as IngredientsList } from './IngredientsList'
export * from './ingredientForm'
export { default as useIngredientsFormsActions } from './useIngredientsFormsActions'
export * from './useIngredientsFormsActions'
export * from './types'
export { default as useGetIngredientFormStatsTree } from './useGetIngredientFormStatsTree'
export { default as getIngredient } from './getIngredient'
================================================
FILE: src/ingredients/ingredientForm.ts
================================================
import { Ingredient } from './types'
import { v4 as uuidv4 } from 'uuid'
import { FoodId } from 'foods'
import { formatAmount } from 'portions'
type IngredientForm = {
fieldId: string
foodId: FoodId
amount: string
notes?: string
portionId: string
}
function getIngredientForm(ingredient: Ingredient): IngredientForm {
const fieldId = uuidv4()
return {
fieldId,
foodId: ingredient.foodId,
amount: formatAmount(ingredient.amount, ingredient.portionId),
portionId: ingredient.portionId,
}
}
function getInsertIngredientFormAnimationKey(fieldId: string) {
return `insert-ingredient-animation-${fieldId}`
}
export type { IngredientForm }
export { getIngredientForm, getInsertIngredientFormAnimationKey }
================================================
FILE: src/ingredients/types.ts
================================================
import { FoodId } from 'foods'
type Ingredient = {
foodId: FoodId
amount: number
portionId: string
}
export type { Ingredient }
================================================
FILE: src/ingredients/useGetIngredientFormStatsTree.ts
================================================
import { useFoods } from 'foods'
import { IngredientForm } from './ingredientForm'
import { StatsTree, objectFromNutritionDataKeys, Stats } from 'stats'
import { DEFAULT_SERVING_SIZE_IN_GRAMS } from 'foods'
import { useGetAmount } from 'portions'
import { useCallback } from 'react'
import amountAsNumber from 'stats/amountAsNumber'
function useGetIngredientFormStatsTree() {
const { foodsById } = useFoods()
const { getAmountFromPortionToGrams } = useGetAmount()
const getIngredientFormStatsTree = useCallback(
(ingredientForm: IngredientForm): StatsTree => {
const food = foodsById[ingredientForm.foodId]
let stats: Stats
if (food) {
const amountInGrams = getAmountFromPortionToGrams(
amountAsNumber(ingredientForm.amount),
ingredientForm.portionId,
food
)
const servingSizeInGrams =
food.servingSizeInGrams || DEFAULT_SERVING_SIZE_IN_GRAMS
const scale = amountInGrams / servingSizeInGrams
stats = {
amountInGrams,
...objectFromNutritionDataKeys(key => Math.round(scale * food[key])),
}
} else {
stats = {
amountInGrams: 0,
...objectFromNutritionDataKeys(() => 0),
}
}
return {
id: ingredientForm.fieldId,
stats,
subtrees: [],
}
},
[foodsById, getAmountFromPortionToGrams]
)
return getIngredientFormStatsTree
}
export default useGetIngredientFormStatsTree
================================================
FILE: src/ingredients/useIngredientsFormsActions.ts
================================================
import { useCallback, SetStateAction } from 'react'
import { DietForm } from 'diets'
import produce from 'immer'
import {
getIngredientForm,
getInsertIngredientFormAnimationKey,
IngredientForm,
} from './ingredientForm'
import { OneTimeCheckActions } from 'general'
import { Food } from 'foods'
import { getIngredient } from 'ingredients'
type Params = {
setDietForm: (action: SetStateAction) => void
oneTimeCheckActions: OneTimeCheckActions
}
function useIngredientsFormsActions({
setDietForm,
oneTimeCheckActions,
}: Params) {
const appendIngredientsForms = useCallback(
(variantFormIndex: number, mealFormIndex: number, foods: Food[]) => {
setDietForm(dietForm =>
produce(dietForm, draftDietForm => {
const ingredients = foods.map(getIngredient)
const ingredientForms = ingredients.map(getIngredientForm)
ingredientForms.forEach(({ fieldId }) => {
oneTimeCheckActions.set(
getInsertIngredientFormAnimationKey(fieldId)
)
})
const { variantsForms } = draftDietForm
const { mealsForms } = variantsForms[variantFormIndex]
const { ingredientsForms } = mealsForms[mealFormIndex]
ingredientsForms.push(...ingredientForms)
})
)
},
[setDietForm, oneTimeCheckActions]
)
const removeIngredientForm = useCallback(
(
variantFormIndex: number,
mealFormIndex: number,
ingredientFormIndex: number
) => {
setDietForm(dietForm =>
produce(dietForm, draftDietForm => {
const { variantsForms } = draftDietForm
const { mealsForms } = variantsForms[variantFormIndex]
const { ingredientsForms } = mealsForms[mealFormIndex]
ingredientsForms.splice(ingredientFormIndex, 1)
})
)
},
[setDietForm]
)
const updateIngredientForm = useCallback(
(
variantFormIndex: number,
mealFormIndex: number,
ingredinetFormIndex: number,
partialIngredientForm: Partial
) => {
setDietForm(dietForm =>
produce(dietForm, draftDietForm => {
const { variantsForms } = draftDietForm
const { mealsForms } = variantsForms[variantFormIndex]
const { ingredientsForms } = mealsForms[mealFormIndex]
const ingredientForm = ingredientsForms[ingredinetFormIndex]
ingredientsForms[ingredinetFormIndex] = {
...ingredientForm,
...partialIngredientForm,
}
})
)
},
[setDietForm]
)
const moveIngredientForm = useCallback(
(
sourceMealFormId: string,
sourceIngredientFormIndex: number,
destinationMealFormId: string,
destinationIngredientFormIndex: number
) => {
setDietForm(dietForm =>
produce(dietForm, draftDietForm => {
const { selectedVariantFormIndex } = dietForm
const { mealsForms } = draftDietForm.variantsForms[
selectedVariantFormIndex
]
const sourceMealForm = mealsForms.find(
({ fieldId }) => fieldId === sourceMealFormId
)
let ingredientForm
if (sourceMealForm) {
ingredientForm =
sourceMealForm.ingredientsForms[sourceIngredientFormIndex]
sourceMealForm.ingredientsForms.splice(sourceIngredientFormIndex, 1)
}
const destinationMealForm = mealsForms.find(
({ fieldId }) => fieldId === destinationMealFormId
)
if (destinationMealForm && ingredientForm) {
destinationMealForm.ingredientsForms.splice(
destinationIngredientFormIndex,
0,
ingredientForm
)
}
})
)
},
[setDietForm]
)
return {
appendIngredientsForms,
removeIngredientForm,
updateIngredientForm,
moveIngredientForm,
}
}
type IngredientsFormsActions = ReturnType
export type { IngredientsFormsActions }
export default useIngredientsFormsActions
================================================
FILE: src/layout/MainLayout.tsx
================================================
import {
createContext,
ReactElement,
ReactNode,
RefObject,
useRef,
} from 'react'
import { Box } from '@chakra-ui/react'
import useHasSideNavigation from './useHasSideNavigation'
export type MainLayoutProps = {
sidebarElement?: ReactElement
children: ReactNode
}
const ContentBoxRefContext = createContext>({
current: null,
})
function MainLayout({ children }: MainLayoutProps) {
const hasSideNavigation = useHasSideNavigation()
const contentBoxRef = useRef(null)
return (
{hasSideNavigation && (
)}
{children}
)
}
export { ContentBoxRefContext }
export default MainLayout
================================================
FILE: src/layout/Page/ElementContainer.tsx
================================================
import { Box, BoxProps } from '@chakra-ui/react'
import { ForwardedRef, ReactNode, forwardRef } from 'react'
type Props = {
children: ReactNode
forwardedRef?: ForwardedRef
} & BoxProps
function ElementContainer({ children, forwardedRef, ...rest }: Props) {
return (
{children}
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/layout/Page/PageBody.tsx
================================================
import { Flex } from '@chakra-ui/react'
import { ReactNode } from 'react'
import ElementContainer from './ElementContainer'
type Props = {
children: ReactNode
}
function PageBody({ children }: Props) {
return (
{children}
)
}
export default PageBody
================================================
FILE: src/layout/Page/PageFooter.tsx
================================================
import { Box } from '@chakra-ui/react'
import { ReactNode, RefObject } from 'react'
import ElementContainer from './ElementContainer'
type Props = {
children: ReactNode
footerContainerRef?: RefObject
}
function PageFooter({ children, footerContainerRef }: Props) {
return (
{children}
)
}
export default PageFooter
================================================
FILE: src/layout/Page/PageHeader.tsx
================================================
import { Box, Flex } from '@chakra-ui/react'
import { ForwardedRef, forwardRef, ReactNode } from 'react'
import ElementContainer from './ElementContainer'
type Props = {
children: ReactNode
forwardedRef?: ForwardedRef
}
function PageHeader({ children, forwardedRef }: Props) {
return (
{children}
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/layout/Page/index.tsx
================================================
import { Box } from '@chakra-ui/react'
import { ReactNode } from 'react'
type Props = {
children: ReactNode
}
function Page({ children }: Props) {
return (
{children}
)
}
export { default as PageHeader } from './PageHeader'
export { default as PageBody } from './PageBody'
export { default as PageFooter } from './PageFooter'
export default Page
================================================
FILE: src/layout/RightAligned.tsx
================================================
import { Flex, FlexProps } from '@chakra-ui/react'
import { ReactNode } from 'react'
type Props = {
children: ReactNode
} & FlexProps
function RightAligned({ children, ...rest }: Props) {
return (
{children}
)
}
export default RightAligned
================================================
FILE: src/layout/index.tsx
================================================
export { default as Page } from './Page'
export * from './Page'
export { default as MainLayout } from './MainLayout'
export * from './MainLayout'
export { default as RightAligned } from './RightAligned'
================================================
FILE: src/layout/useHasSideNavigation.ts
================================================
// import { useScreenSize } from 'general'
function useHasSideNavigation() {
/*const screenSize = useScreenSize()
return screenSize >= ScreenSize.Large*/
return false
}
export default useHasSideNavigation
================================================
FILE: src/meals/MealsList/EmptyList.tsx
================================================
import { Text, Center, chakra, Button, VStack } from '@chakra-ui/react'
import { Plus } from 'react-feather'
const PlusStyled = chakra(Plus)
type Props = {
onAddMeal: () => void
}
function EmptyList({ onAddMeal }: Props) {
return (
You haven't added any meals to this day yet
Days can be specific weekdays or just types of days. For example: a
training or a rest day.
}
>
Add meal
)
}
export default EmptyList
================================================
FILE: src/meals/MealsList/MealItem/Header/MenuOrDrawer.tsx
================================================
import { RightAligned } from 'layout'
import { MenuOrDrawer as MenuOrDrawerBase } from 'general'
import { ReactElement } from 'react'
type Props = {
children: ReactElement[]
}
function MenuOrDrawer({ children }: Props) {
return (
{children}
)
}
export default MenuOrDrawer
================================================
FILE: src/meals/MealsList/MealItem/Header/Name.tsx
================================================
import { BoxProps, Input, Flex } from '@chakra-ui/react'
import { useDietFormActions } from 'diets'
import { MealForm } from 'meals'
import { RefObject, ChangeEvent } from 'react'
type Props = {
variantIndex: number
mealForm: MealForm
index: number
getMealNameInputRefById: (id: string) => RefObject
} & BoxProps
function Name({
variantIndex,
mealForm,
index,
getMealNameInputRefById,
...rest
}: Props) {
const dietFormActions = useDietFormActions()
function onNameChange(event: ChangeEvent) {
const { value } = event.target
dietFormActions.updateMealForm(variantIndex, index, {
name: value,
})
}
return (
)
}
export default Name
================================================
FILE: src/meals/MealsList/MealItem/Header/getMenuOrDrawerItems.tsx
================================================
import { chakra } from '@chakra-ui/react'
import { Plus, Trash2, Copy, Edit } from 'react-feather'
import { MealForm } from 'meals'
import { MenuOrDrawerItem, MenuOrDrawerSeparator } from 'general'
const PlusStyled = chakra(Plus)
const Trash2Styled = chakra(Trash2)
const CopyStyled = chakra(Copy)
const EditStyled = chakra(Edit)
type Params = {
onRemove: () => void
onEditNotes: () => void
onAddIngredient: () => void
onClone: () => void
mealForm: MealForm
}
function getMenuOrDrawerItems({
onRemove,
onAddIngredient,
onClone,
onEditNotes,
mealForm,
}: Params) {
return [
}
key="addFoods"
onClick={() => onAddIngredient()}
>
Add foods
,
,
}
onClick={() => onEditNotes()}
>
{mealForm.notes ? 'Edit notes' : 'Add notes'}
,
}
onClick={() => onClone()}
>
Duplicate
,
}
onClick={() => onRemove()}
>
Remove
,
]
}
export default getMenuOrDrawerItems
================================================
FILE: src/meals/MealsList/MealItem/Header/index.tsx
================================================
import { BoxProps } from '@chakra-ui/react'
import { MealForm } from 'meals'
import { Stat, StatsLayout } from 'stats'
import { RefObject } from 'react'
import Name from './Name'
import MenuOrDrawer from './MenuOrDrawer'
import { Stats } from 'stats'
import { ContextMenuFlex } from 'general'
import getMenuOrDrawerItems from './getMenuOrDrawerItems'
type Props = {
mealForm: MealForm
variantIndex: number
index: number
onAddIngredient: () => void
onRemove: () => void
onClone: () => void
onEditNotes: () => void
getMealNameInputRefById: (id: string) => RefObject
ingredientsStatsSum: Stats
} & BoxProps
function Header({
mealForm,
variantIndex,
index,
onRemove,
onClone,
onAddIngredient,
onEditNotes,
getMealNameInputRefById,
ingredientsStatsSum,
...rest
}: Props) {
const menuOrDrawerItems = getMenuOrDrawerItems({
onAddIngredient,
onRemove,
onClone,
onEditNotes,
mealForm,
})
return (
}
energyElement={
}
proteinElement={
}
carbsElement={
}
fatElement={
}
menuElement={{menuOrDrawerItems}}
/>
)
}
export default Header
================================================
FILE: src/meals/MealsList/MealItem/Notes.tsx
================================================
import { Box, Text } from '@chakra-ui/react'
type Props = {
notes: string
}
function Notes({ notes }: Props) {
return (
{notes}
)
}
export default Notes
================================================
FILE: src/meals/MealsList/MealItem/PresenceAnimation.tsx
================================================
import { ReactNode } from 'react'
import { motion } from 'framer-motion'
type Props = {
children: ReactNode
shouldAnimate: boolean
onAnimationComplete: () => void
isVisible: boolean
isDragging: boolean
}
const variants = {
open: {
opacity: 1,
height: 'auto',
},
collapsed: { opacity: 0, height: 0, x: 0 },
}
function PresenceAnimation({
children,
onAnimationComplete,
shouldAnimate,
isVisible,
isDragging,
}: Props) {
return (
{children}
)
}
export default PresenceAnimation
================================================
FILE: src/meals/MealsList/MealItem/index.tsx
================================================
import { MealForm } from 'meals'
import { Flex, FlexProps, useDisclosure, Divider, Box } from '@chakra-ui/react'
import Header from './Header'
import { RefObject, memo } from 'react'
import { Draggable } from 'react-beautiful-dnd'
import { IngredientsList } from 'ingredients'
import { FoodsDrawer } from 'foods'
import PresenceAnimation from './PresenceAnimation'
import useMealFormEvents from './useMealFormEvents'
import { EditNotesModal } from 'notes'
import Notes from './Notes'
import useGetAndUpdateStats from './useGetAndUpdateStats'
type Props = {
mealForm: MealForm
index: number
variantIndex: number
onRemove: (variantIndex: number, index: number) => void
getMealNameInputRefById: (id: string) => RefObject
onFirstAppear: (mealForm: MealForm) => void
selectedVariantFormFieldId: string
isDragging: boolean
} & FlexProps
function MealItem({
mealForm,
index,
onRemove,
getMealNameInputRefById,
variantIndex,
selectedVariantFormFieldId,
onFirstAppear,
isDragging,
...rest
}: Props) {
const foodsDrawerDisclosure = useDisclosure()
const mealFormEvents = useMealFormEvents({
mealForm,
variantIndex,
index,
onFirstAppear,
onRemove,
foodsDrawerDisclosure,
})
const editNotesModalDisclosure = useDisclosure()
const { mealFormStatsTree, ingredientsStats } = useGetAndUpdateStats({
mealForm,
index,
selectedVariantFormFieldId,
})
return (
{(provided, snapshot) => (
{mealForm.notes && }
)}
)
}
export default memo(MealItem)
================================================
FILE: src/meals/MealsList/MealItem/useGetAndUpdateStats.ts
================================================
import { MealForm } from 'meals'
import { useGetIngredientFormStatsTree } from 'ingredients'
import { getStatsTree, useUpdateMealStats } from 'stats'
import { useMemo } from 'react'
type Params = {
mealForm: MealForm
index: number
selectedVariantFormFieldId: string
}
function useGetAndUpdateStats({
mealForm,
index,
selectedVariantFormFieldId,
}: Params) {
const getIngredientFormStatsTree = useGetIngredientFormStatsTree()
const mealFormStatsTree = useMemo(
() =>
getStatsTree({
id: mealForm.fieldId,
subtrees: mealForm.ingredientsForms.map(ingredientForm =>
getIngredientFormStatsTree(ingredientForm)
),
}),
[mealForm.fieldId, mealForm.ingredientsForms, getIngredientFormStatsTree]
)
const ingredientsStats = useMemo(
() => mealFormStatsTree.subtrees.map(({ stats }) => stats),
[mealFormStatsTree]
)
useUpdateMealStats({
stats: mealFormStatsTree.stats,
selectedVariantFormFieldId,
index,
})
return {
ingredientsStats,
mealFormStatsTree,
}
}
export default useGetAndUpdateStats
================================================
FILE: src/meals/MealsList/MealItem/useMealFormEvents.ts
================================================
import { MealForm, getInsertMealFormAnimationKey } from 'meals'
import { useState } from 'react'
import { useOneTimeCheckActions } from 'general'
import { useDietFormActions } from 'diets'
import { Food } from 'foods'
import { UseDisclosureReturn } from '@chakra-ui/hooks'
import { useToast } from '@chakra-ui/toast'
type Params = {
mealForm: MealForm
index: number
variantIndex: number
onRemove: (variantIndex: number, index: number) => void
onFirstAppear: (mealForm: MealForm) => void
foodsDrawerDisclosure: UseDisclosureReturn
}
function useMealFormEvents({
mealForm,
index,
onRemove,
variantIndex,
onFirstAppear,
foodsDrawerDisclosure,
}: Params) {
const [isVisible, setIsVisible] = useState(true)
const oneTimeCheckActions = useOneTimeCheckActions()
const dietFormActions = useDietFormActions()
const toast = useToast()
const shouldAnimate = oneTimeCheckActions.checkAndReset(
getInsertMealFormAnimationKey(mealForm.fieldId)
)
function onAnimationComplete() {
if (shouldAnimate) {
onFirstAppear(mealForm)
} else if (!isVisible) {
onRemove(variantIndex, index)
}
}
function onRemoveRequest() {
setIsVisible(false)
}
function onClone() {
dietFormActions.duplicateMealForm(variantIndex, index)
}
function onEditNotes(notes?: string) {
toast({
status: 'success',
position: 'top',
title: mealForm.notes
? 'Your notes were edited'
: 'Your notes were added',
duration: 2000,
isClosable: true,
})
dietFormActions.updateMealForm(variantIndex, index, {
notes,
})
}
function onAddFoods(foods: Food[]) {
dietFormActions.appendIngredientsForms(variantIndex, index, foods)
foodsDrawerDisclosure.onClose()
}
return {
onAnimationComplete,
shouldAnimate,
onRemoveRequest,
isVisible,
onClone,
onAddFoods,
onEditNotes,
}
}
export default useMealFormEvents
================================================
FILE: src/meals/MealsList/MealsControls.tsx
================================================
import { Flex, chakra, Button } from '@chakra-ui/react'
import { MealForm } from 'meals'
import { Plus } from 'react-feather'
const PlusStyled = chakra(Plus)
type Props = {
mealsForms: MealForm[]
onAddMeal: () => void
}
function MealsControls({ mealsForms, onAddMeal }: Props) {
return (
}
>
Add meal
)
}
export default MealsControls
================================================
FILE: src/meals/MealsList/index.tsx
================================================
import { BoxProps, Flex, Box } from '@chakra-ui/react'
import MealItem from './MealItem'
import { useRef, memo } from 'react'
import { useGetRefForId } from 'dom'
import { Droppable } from 'react-beautiful-dnd'
import { useDietFormActions } from 'diets'
import { MealForm } from 'meals'
import useScrollToAndFocusMeal from './useScrollToAndFocusMeal'
import EmptyList from './EmptyList'
import MealsControls from './MealsControls'
type Props = {
mealsForms: MealForm[]
selectedVariantFormIndex: number
selectedVariantFormFieldId: string
headerHeight: number
onAddMeal: () => void
} & BoxProps
function MealsList({
mealsForms,
selectedVariantFormIndex,
selectedVariantFormFieldId,
headerHeight,
onAddMeal,
...rest
}: Props) {
const getMealNameInputRefById = useGetRefForId()
const scrollTargetRef = useRef(null)
const { onScrollToMeal } = useScrollToAndFocusMeal({
scrollTargetRef,
getMealNameInputRefById,
})
const dietFormActions = useDietFormActions()
return (
{(provided, snapshot) => (
{mealsForms.length > 0 ? (
mealsForms.map((mealForm, index) => (
))
) : (
)}
{provided.placeholder}
{mealsForms.length > 0 && (
<>
>
)}
)}
)
}
export default memo(MealsList)
================================================
FILE: src/meals/MealsList/useScrollToAndFocusMeal.ts
================================================
import { MealForm } from 'meals'
import { useScrollTo } from 'dom'
import { RefObject, useCallback } from 'react'
import { isMobile } from 'react-device-detect'
type Params = {
getMealNameInputRefById: (id: string) => RefObject
scrollTargetRef: RefObject
}
function useScrollToAndFocusMeal({ getMealNameInputRefById }: Params) {
const scrollTo = useScrollTo()
const onScrollToMeal = useCallback(
async (mealForm: MealForm) => {
const mealNameInputRef = getMealNameInputRefById(mealForm.fieldId)
if (mealNameInputRef.current) {
await scrollTo(mealNameInputRef.current)
}
if (mealNameInputRef.current && !isMobile) {
mealNameInputRef.current.setSelectionRange(
0,
mealNameInputRef.current.value.length
)
mealNameInputRef.current.focus()
}
},
[getMealNameInputRefById, scrollTo]
)
return { onScrollToMeal }
}
export default useScrollToAndFocusMeal
================================================
FILE: src/meals/PdfMealsList/Notes.tsx
================================================
import { Text, StyleSheet, View } from '@react-pdf/renderer'
import getComputedColorFromChakra from 'theme/getComputedColorFromChakra'
type Props = {
notes: string
}
function Notes({ notes }: Props) {
return (
{notes}
)
}
const styles = StyleSheet.create({
root: {
padding: 12,
borderTopWidth: 1,
fontSize: 14,
},
text: {
flexDirection: 'row',
flex: 1,
},
})
export default Notes
================================================
FILE: src/meals/PdfMealsList/PdfMealItem.tsx
================================================
import { Text, StyleSheet, View } from '@react-pdf/renderer'
import { MealForm } from 'meals'
import { Style } from '@react-pdf/types/style'
import getComputedColorFromChakra from 'theme/getComputedColorFromChakra'
import { Stats } from 'stats'
import PdfStat from 'stats/PdfStat'
import PdfStatsLayout from 'stats/PdfStatsLayout'
import { Food } from 'foods'
import PdfIngredientsList from 'ingredients/PdfIngredientsList'
import { Portion } from 'portions'
import Notes from './Notes'
type Props = {
mealForm: MealForm
style?: Style
stats: Stats
ingredientsFormsStats: Stats[]
foodsById: Record
portionsById: Record
}
function PdfMealItem({
mealForm,
stats,
ingredientsFormsStats,
style = {},
foodsById,
portionsById,
}: Props) {
const { ingredientsForms } = mealForm
return (
{mealForm.name || 'Untitled meal'}
}
energyElement={
}
proteinElement={
}
carbsElement={
}
fatElement={}
/>
{mealForm.notes && }
)
}
const styles = StyleSheet.create({
root: {
borderWidth: 1,
borderRadius: 8,
},
name: {
fontSize: 14,
fontWeight: 'medium',
marginLeft: 12,
},
header: {
backgroundColor: 'white',
borderTopLeftRadius: 7,
borderTopRightRadius: 7,
paddingTop: 12,
paddingBottom: 12,
},
})
export default PdfMealItem
================================================
FILE: src/meals/PdfMealsList/index.tsx
================================================
import { View } from '@react-pdf/renderer'
import { Food } from 'foods'
import { MealForm } from 'meals/mealForm'
import { Portion } from 'portions'
import { StatsTree } from 'stats'
import PdfMealItem from './PdfMealItem'
type Props = {
mealsForms: MealForm[]
mealsFormsStatsTrees: StatsTree[]
foodsById: Record
portionsById: Record
}
function PdfMealsList({
mealsForms,
mealsFormsStatsTrees,
foodsById,
portionsById,
}: Props) {
return (
{mealsForms.map((mealForm, index) => {
const { stats, subtrees } = mealsFormsStatsTrees[index]
return (
stats)}
foodsById={foodsById}
portionsById={portionsById}
/>
)
})}
)
}
export default PdfMealsList
================================================
FILE: src/meals/index.ts
================================================
export { default as MealsList } from './MealsList'
export { default as useMealsFormsActions } from './useMealsFormsActions'
export * from './useMealsFormsActions'
export * from './mealForm'
export * from './types'
export { default as useGetMealFormStatsTree } from './useGetMealFormStatsTree'
================================================
FILE: src/meals/mealForm.ts
================================================
import { Meal } from './types'
import { getIngredientForm, IngredientForm } from 'ingredients'
import { v4 as uuidv4 } from 'uuid'
type MealForm = {
fieldId: string
name: string
notes?: string
ingredientsForms: IngredientForm[]
}
function getMealForm(meal?: Meal): MealForm {
const fieldId = uuidv4()
if (meal) {
return {
fieldId,
name: meal.name,
ingredientsForms: meal.ingredients.map(ingredient =>
getIngredientForm(ingredient)
),
}
}
return {
fieldId,
name: '',
ingredientsForms: [],
}
}
function getInsertMealFormAnimationKey(fieldId: string) {
return `insert-meal-animmation-${fieldId}`
}
export type { MealForm }
export { getMealForm, getInsertMealFormAnimationKey }
================================================
FILE: src/meals/types.ts
================================================
import { Ingredient } from 'ingredients'
type Meal = {
name: string
ingredients: Ingredient[]
}
export type { Meal }
================================================
FILE: src/meals/useGetMealFormStatsTree.ts
================================================
import { getStatsTree, StatsTree } from 'stats'
import { useGetIngredientFormStatsTree } from 'ingredients'
import { MealForm } from 'meals'
import { useCallback } from 'react'
function useGetMealFormStatsTree() {
const getIngredientFormStatsTree = useGetIngredientFormStatsTree()
const getMealFormStatsTree = useCallback(
(mealForm: MealForm): StatsTree => {
return getStatsTree({
id: mealForm.fieldId,
subtrees: mealForm.ingredientsForms.map(ingredientForm =>
getIngredientFormStatsTree(ingredientForm)
),
})
},
[getIngredientFormStatsTree]
)
return getMealFormStatsTree
}
export default useGetMealFormStatsTree
================================================
FILE: src/meals/useMealsFormsActions.ts
================================================
import { useCallback, SetStateAction } from 'react'
import { DietForm } from 'diets'
import produce from 'immer'
import {
getInsertMealFormAnimationKey,
getMealForm,
MealForm,
} from './mealForm'
import { OneTimeCheckActions } from 'general'
import { duplicate } from 'form'
import { getDuplicatedName } from 'form/names'
type Params = {
setDietForm: (action: SetStateAction) => void
oneTimeCheckActions: OneTimeCheckActions
}
function useMealsFormsActions({ setDietForm, oneTimeCheckActions }: Params) {
const appendMealForm = useCallback(
(mealForm?: MealForm) =>
setDietForm(
produce(draftDietForm => {
const mealFormToAppend = mealForm || getMealForm()
const { selectedVariantFormIndex, variantsForms } = draftDietForm
oneTimeCheckActions.set(
getInsertMealFormAnimationKey(mealFormToAppend.fieldId)
)
variantsForms[selectedVariantFormIndex].mealsForms.push(
mealFormToAppend
)
})
),
[setDietForm, oneTimeCheckActions]
)
const removeMealForm = useCallback(
(variantIndex: number, mealFormIndex: number) =>
setDietForm(
produce(draftDietForm => {
draftDietForm.variantsForms[variantIndex].mealsForms.splice(
mealFormIndex,
1
)
})
),
[setDietForm]
)
const moveMealForm = useCallback(
(fromIndex: number, toIndex: number) =>
setDietForm(
produce(draftDietForm => {
const { variantsForms, selectedVariantFormIndex } = draftDietForm
const mealsForms = variantsForms[selectedVariantFormIndex].mealsForms
const mealForm = mealsForms[fromIndex]
mealsForms.splice(fromIndex, 1)
mealsForms.splice(toIndex, 0, mealForm)
})
),
[setDietForm]
)
const updateMealForm = useCallback(
(
variantFormIndex: number,
mealFormIndex: number,
partialMealForm: Partial
) => {
setDietForm(
produce(draftDietForm => {
const { mealsForms } = draftDietForm.variantsForms[variantFormIndex]
const mealForm = mealsForms[mealFormIndex]
mealsForms[mealFormIndex] = {
...mealForm,
...partialMealForm,
} as MealForm
})
)
},
[setDietForm]
)
const duplicateMealForm = useCallback(
(variantFormIndex: number, mealFormIndex: number) =>
setDietForm(
produce(draftDietForm => {
const { mealsForms } = draftDietForm.variantsForms[variantFormIndex]
const mealForm = mealsForms[mealFormIndex]
const newMealForm = {
...duplicate(mealForm),
name: getDuplicatedName(mealFormIndex, mealsForms),
}
appendMealForm(newMealForm)
})
),
[setDietForm, appendMealForm]
)
return {
appendMealForm,
removeMealForm,
moveMealForm,
updateMealForm,
duplicateMealForm,
}
}
type MealsFormsActions = ReturnType
export type { MealsFormsActions }
export default useMealsFormsActions
================================================
FILE: src/notes/EditNotesModal/Content/Form/Header.tsx
================================================
import { ModalHeader, Text } from '@chakra-ui/react'
type Props = {
ownerName: string
notes?: string
}
function Header({ ownerName, notes }: Props) {
const titlePrefix = notes ? 'Edit notes of' : 'Add notes to'
return (
{titlePrefix}{' '}
{ownerName}
)
}
export default Header
================================================
FILE: src/notes/EditNotesModal/Content/Form/index.tsx
================================================
import {
ModalFooter,
ModalBody,
Button,
FormControl,
Textarea,
FormLabel,
FormErrorMessage,
ModalContent,
ModalCloseButton,
Collapse,
Box,
} from '@chakra-ui/react'
import { RefObject } from 'react'
import { useFormContext } from 'react-hook-form'
import { useMergeRefs } from '@chakra-ui/react'
import { useFormError } from 'form'
import { NotesForm } from 'notes'
import { useOneTimeCheckActions } from 'general'
import Header from './Header'
type Props = {
onClose: () => void
initialRef: RefObject
onEditNotes: (notes?: string) => void
fieldId: string
ownerName: string
notes?: string
textAreaHeight?: string | number
}
function Form({
ownerName,
notes,
onClose,
initialRef,
onEditNotes,
fieldId,
textAreaHeight,
}: Props) {
const { register, handleSubmit } = useFormContext()
const notesRegister = register('notes')
const notesInputRef = useMergeRefs(notesRegister.ref, initialRef)
const oneTimeCheckActions = useOneTimeCheckActions()
const onSubmit = handleSubmit((form: NotesForm) => {
oneTimeCheckActions.set(`notes-${fieldId}`)
onEditNotes(form.notes || undefined)
onClose()
})
const { errorMessage, isInvalid } = useFormError('name')
return (
)
}
export default Form
================================================
FILE: src/notes/EditNotesModal/Content/NotesFormProvider.tsx
================================================
import { FormProvider, useForm } from 'react-hook-form'
import { yupResolver } from '@hookform/resolvers/yup'
import { ReactNode } from 'react'
import { getNotesForm, NotesForm, notesFormSchema } from 'notes'
type Props = {
children: ReactNode
notes?: string
}
function NotesFormProvider({ children, notes }: Props) {
const defaultValues = getNotesForm(notes)
const formMethods = useForm({
defaultValues,
mode: 'onChange',
resolver: yupResolver(notesFormSchema),
})
return {children}
}
export default NotesFormProvider
================================================
FILE: src/notes/EditNotesModal/Content/index.tsx
================================================
import { RefObject } from 'react'
import NotesFormProvider from './NotesFormProvider'
import Form from './Form'
type Props = {
onClose: () => void
initialRef: RefObject
onEditNotes: (notes?: string) => void
fieldId: string
ownerName: string
notes?: string
textAreaHeight?: string | number
}
function Content({
ownerName,
onClose,
initialRef,
onEditNotes,
fieldId,
notes,
textAreaHeight,
}: Props) {
return (
)
}
export default Content
================================================
FILE: src/notes/EditNotesModal/Content/notesForm.ts
================================================
import { object, string } from 'yup'
type NotesForm = {
notes: string
}
function getNotesForm(notes?: string): NotesForm {
return {
notes: notes || '',
}
}
const notesFormSchema = object().shape({
name: string(),
})
export { getNotesForm, notesFormSchema }
export type { NotesForm }
================================================
FILE: src/notes/EditNotesModal/index.tsx
================================================
import { Modal, ModalOverlay, ModalProps } from '@chakra-ui/react'
import { useRef } from 'react'
import Content from './Content'
type Props = {
onClose: () => void
isOpen: boolean
notes?: string
onEditNotes: (notes?: string) => void
fieldId: string
ownerName: string
textAreaHeight?: string | number
} & Omit
function EditNotesModal({
onClose,
isOpen,
notes,
onEditNotes,
fieldId,
ownerName,
textAreaHeight,
...rest
}: Props) {
const initialRef = useRef(null)
const finalFocusRef = useRef(null)
return (
)
}
export default EditNotesModal
================================================
FILE: src/notes/index.ts
================================================
export { default as EditNotesModal } from './EditNotesModal'
export * from './EditNotesModal'
export * from './notesForm'
================================================
FILE: src/notes/notesForm.ts
================================================
import { object, string } from 'yup'
type NotesForm = {
notes: string
}
function getNotesForm(notes?: string): NotesForm {
return {
notes: notes || '',
}
}
const notesFormSchema = object().shape({
name: string(),
})
export { getNotesForm, notesFormSchema }
export type { NotesForm }
================================================
FILE: src/persistence/DownloadButton.tsx
================================================
import { Button, ButtonProps } from '@chakra-ui/react'
import { useBlobUrl } from 'persistence'
import prettyBytes from 'pretty-bytes'
type Props = {
blob?: Blob
onClose: () => void
fileName: string
label: string
} & ButtonProps
function DownloadButton({ blob, onClose, fileName, label, ...rest }: Props) {
const { url } = useBlobUrl({ blob })
return (
)
}
export default DownloadButton
================================================
FILE: src/persistence/file.ts
================================================
function createFileInput(accept: string) {
const input = document.createElement('input')
input.type = 'file'
input.multiple = false
input.accept = accept
return input
}
function selectFile(accept: string) {
return new Promise(resolve => {
const input = createFileInput(accept)
input.addEventListener('change', function onChange(this: HTMLInputElement) {
const { files } = this
if (files && files.length > 0) {
resolve(files[0])
}
})
input.dispatchEvent(new MouseEvent('click'))
})
}
function readFile(file: File) {
return new Promise((resolve, reject) => {
const fileReader = new FileReader()
fileReader.onload = () => {
const { result } = fileReader
resolve(result as string)
}
fileReader.onerror = () => {
const { error } = fileReader
fileReader.abort()
reject(error)
}
fileReader.readAsText(file)
})
}
export { selectFile, readFile }
================================================
FILE: src/persistence/fixWhiteSpace.tsx
================================================
function fixWhiteSpace(text: string) {
return text.replace(/\\n/g, '\n').replace(/\r/g, '\r').replace(/\t/g, '\t')
}
export default fixWhiteSpace
================================================
FILE: src/persistence/getUntitledFileName.ts
================================================
type Params = {
prefix?: string
}
function getUntitledFileName({ prefix = 'Untitled' }: Params = {}) {
const date = new Date()
const dateString = date.toISOString()
const dateStringParts = dateString.split('.')
return `${prefix}-${dateStringParts[0]}`
}
export default getUntitledFileName
================================================
FILE: src/persistence/index.ts
================================================
export { default as useSaveValue } from './useSaveValue'
export * from './file'
export { default as useBlobUrl } from './useBlobUrl'
export { default as DownloadButton } from './DownloadButton'
export { default as getUntitledFileName } from './getUntitledFileName'
export { default as useFileImportError } from './useImportFileError'
export { default as fixWhiteSpace } from './fixWhiteSpace'
================================================
FILE: src/persistence/useBlobUrl.ts
================================================
import { useEffect, useState } from 'react'
type Params = {
blob?: Blob
}
function useBlobUrl({ blob }: Params) {
const [url, setUrl] = useState()
useEffect(() => {
if (blob) {
const blobUrl = URL.createObjectURL(blob)
setUrl(blobUrl)
return () => {
URL.revokeObjectURL(blobUrl)
}
}
}, [blob])
return {
url,
}
}
export default useBlobUrl
================================================
FILE: src/persistence/useImportFileError.ts
================================================
import { useToast, UseToastOptions } from '@chakra-ui/toast'
const COMMON_TOAST_OPTIONS: UseToastOptions = {
isClosable: true,
position: 'top',
duration: null,
status: 'error',
}
type OnErrorParams = {
file: File
error: any
}
function useFileImportError() {
const toast = useToast()
function showCouldNotLoadFileToast(file: File) {
toast({
...COMMON_TOAST_OPTIONS,
title: `File ${file.name} could not be loaded`,
})
}
function showCouldNotParseFileToast(file: File) {
toast({
...COMMON_TOAST_OPTIONS,
title: `File ${file.name} contains invalid data`,
})
}
function showErrorToast(file: File, error: any) {
const { message } = error
toast({
...COMMON_TOAST_OPTIONS,
title: `File ${file.name} could not be imported`,
description: message,
})
}
function onError({ error, file }: OnErrorParams) {
if (error instanceof DOMException) {
showCouldNotLoadFileToast(file)
} else if (error instanceof SyntaxError) {
showCouldNotParseFileToast(file)
} else {
showErrorToast(file, error)
}
}
return {
onError,
}
}
export default useFileImportError
================================================
FILE: src/persistence/useSaveValue.ts
================================================
import { useEffect } from 'react'
const TIMEOUT = 150
type Params = {
value: any
key: string
isEnabled?: boolean
}
function useSaveValue({ value, key, isEnabled = true }: Params) {
useEffect(() => {
if (isEnabled) {
const timeoutId = window.setTimeout(() => {
try {
const valueString = JSON.stringify(value)
localStorage.setItem(key, valueString)
} catch (error) {
// Do nothing
}
}, TIMEOUT)
return () => {
window.clearTimeout(timeoutId)
}
}
}, [value, key, isEnabled])
}
export default useSaveValue
================================================
FILE: src/portions/PortionsMenuOrDrawer/Drawer/PortionItem.tsx
================================================
import { Box, BoxProps, Flex, Text } from '@chakra-ui/react'
import { Portion, getPortionDescription } from 'portions'
import { Check } from 'react-feather'
type Props = {
portion: Portion
isSelected: boolean
} & BoxProps
function PortionItem({ portion, isSelected, ...rest }: Props) {
const { unit } = portion
return (
{unit}{' '}
{getPortionDescription(portion)}
{isSelected && (
)}
)
}
export default PortionItem
================================================
FILE: src/portions/PortionsMenuOrDrawer/Drawer/index.tsx
================================================
import {
Drawer as DrawerBase,
DrawerBody,
DrawerHeader,
DrawerOverlay,
DrawerContent,
DrawerCloseButton,
} from '@chakra-ui/react'
import { Portion } from 'portions'
import PortionItem from './PortionItem'
type Props = {
isOpen: boolean
onClose: () => void
onChange: (portion: Portion) => void
selectedPortionId: string
portions: Portion[]
}
function Drawer({
portions,
isOpen,
onClose,
onChange,
selectedPortionId,
}: Props) {
return (
Portions
{portions.map(portion => {
const { id } = portion
const isSelected = id === selectedPortionId
return (
{
onClose()
onChange(portion)
}}
/>
)
})}
)
}
export default Drawer
================================================
FILE: src/portions/PortionsMenuOrDrawer/Menu.tsx
================================================
import { chakra, Text } from '@chakra-ui/react'
import { Check } from 'react-feather'
import { Menu as MenuBase, MenuItem } from 'general'
import Trigger from './Trigger'
import { getPortionDescription, Portion } from 'portions'
const CheckStyled = chakra(Check)
type Props = {
selectedPortionId: string
onChange: (portion: Portion) => void
portions: Portion[]
}
function Menu({ portions, onChange, selectedPortionId }: Props) {
return (
}
>
{portions.map(portion => {
const { id, unit } = portion
const isSelected = id === selectedPortionId
return (
)
})}
)
}
export default Menu
================================================
FILE: src/portions/PortionsMenuOrDrawer/Trigger.tsx
================================================
import { ForwardedRef, forwardRef } from 'react'
import { Button } from '@chakra-ui/react'
import { usePortions } from 'portions'
type Props = {
selectedPortionId: string
forwardedRef?: ForwardedRef
onClick?: () => void
}
function Trigger({ forwardedRef, selectedPortionId, ...rest }: Props) {
const { portionsById } = usePortions()
const portion = portionsById[selectedPortionId]
return (
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/portions/PortionsMenuOrDrawer/index.tsx
================================================
import { useScreenSize, ScreenSize } from 'general'
import Drawer from './Drawer'
import Trigger from './Trigger'
import { useDisclosure } from '@chakra-ui/hooks'
import Menu from './Menu'
import { Portion, usePortions } from 'portions'
import { Food } from 'foods'
type Props = {
onPortionChange: (portion: Portion) => void
selectedPortionId: string
food: Food
}
function PortionsMenuOrDrawer({
food,
onPortionChange,
selectedPortionId,
}: Props) {
const screenSize = useScreenSize()
const modalDisclosure = useDisclosure()
const { allPortions, weightBasedPortions } = usePortions()
const portions = food.volume ? allPortions : weightBasedPortions
if (screenSize < ScreenSize.Medium) {
return (
<>
>
)
}
return (
)
}
export default PortionsMenuOrDrawer
================================================
FILE: src/portions/PortionsSelect.tsx
================================================
import { SelectProps, Select } from '@chakra-ui/select'
import { Portion } from 'portions'
import { ForwardedRef, forwardRef } from 'react'
type Props = {
forwardedRef?: ForwardedRef
portions: Portion[]
} & SelectProps
function PortionsSelect({ children, forwardedRef, portions, ...rest }: Props) {
return (
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/portions/defaultPortions.ts
================================================
import { Portion } from './types'
const defaultPortions: Portion[] = [
{
id: 'grams',
unit: 'g',
gramsPerAmount: 1,
singular: 'gram',
},
{
id: 'ounces',
unit: 'oz',
gramsPerAmount: 28.34952,
singular: 'ounce',
},
{
id: 'milliliters',
unit: 'ml',
millilitersPerAmount: 1,
singular: 'milliliter',
},
{
id: 'teaspoons',
unit: 'tsp',
millilitersPerAmount: 5,
singular: 'teaspoon',
},
{
id: 'tablespoons',
unit: 'tbsp',
millilitersPerAmount: 15,
singular: 'tablespoon',
},
{
id: 'fluid ounces',
unit: 'fl oz',
millilitersPerAmount: 30,
singular: 'fluid ounce',
},
{
id: 'cups',
unit: 'cup',
millilitersPerAmount: 240,
singular: 'cup',
},
]
export default defaultPortions
================================================
FILE: src/portions/formatAmount.ts
================================================
import formatQuantity from 'format-quantity'
function formatAsNumber(amount: number) {
const amountStringFixedTo1 = amount.toFixed(1)
const amountFixedTo1 = Number(amountStringFixedTo1)
return Number.isInteger(amountFixedTo1)
? amountFixedTo1.toString()
: amountStringFixedTo1
}
function formatAmount(amount: number, portionId: string): string {
if (portionId === 'grams') {
return Math.round(amount).toString()
}
if (
portionId === 'ounces' ||
portionId === 'milliliters' ||
portionId === 'fluid ounces'
) {
return formatAsNumber(amount)
}
const formattedAsFractions = formatQuantity(amount) || ''
if (formattedAsFractions.includes('.')) {
return formatAsNumber(amount)
}
return formattedAsFractions
}
export default formatAmount
================================================
FILE: src/portions/getAmountFromPortionsToGrams.ts
================================================
import { Food } from 'foods'
import { Portion } from 'portions'
import getToGramsConversionFactor from './getToGramsConversionFactor'
function getAmountFromPortionToGrams(
amountInGrams: number,
portionId: string,
food: Food,
portionsById: Record
) {
const portion = portionsById[portionId]
const factor = getToGramsConversionFactor(portion, food, portionsById)
return amountInGrams * factor
}
export default getAmountFromPortionToGrams
================================================
FILE: src/portions/getIngredientPortionDescription.ts
================================================
import { Food, FoodId } from 'foods'
import { IngredientForm } from 'ingredients'
import amountAsNumber from 'stats/amountAsNumber'
import { Portion } from './types'
import getAmountFromPortionToGrams from './getAmountFromPortionsToGrams'
const UNITS_WITH_DISTANCE = ['oz', 'tsp', 'tbsp', 'fl oz', 'cup']
function getIngredientPortionDescription(
ingredientForm: IngredientForm,
foodsById: Record,
portionsById: Record
) {
const { portionId, foodId, amount } = ingredientForm
const portion = portionsById[portionId]
const distance = UNITS_WITH_DISTANCE.includes(portion.unit) ? ' ' : ''
const mainPart = `${amount || 0}${distance}${portion.unit}`
const { gramsPerAmount, millilitersPerAmount } = portion
if (gramsPerAmount !== 1 || millilitersPerAmount) {
const weightInGrams = Math.round(
getAmountFromPortionToGrams(
amountAsNumber(amount),
portion.id,
foodsById[foodId],
portionsById
)
)
return `${mainPart} (${weightInGrams}g)`
}
return mainPart
}
export default getIngredientPortionDescription
================================================
FILE: src/portions/getPortionDescription.ts
================================================
import { Portion } from 'portions'
function getPortionDescription(portion: Portion) {
const { id, millilitersPerAmount } = portion
if (millilitersPerAmount && id !== 'milliliters') {
return `(${millilitersPerAmount} ml)`
}
return ''
}
export default getPortionDescription
================================================
FILE: src/portions/getToGramsConversionFactor.ts
================================================
import { Food } from 'foods'
import { Portion } from 'portions'
function getToGramsConversionFactor(
portion: Portion,
food: Food,
portionsById: Record
): number {
const { gramsPerAmount, millilitersPerAmount } = portion
if (gramsPerAmount) {
return gramsPerAmount
}
if (millilitersPerAmount && food.volume) {
const { portionId, weightInGrams } = food.volume
const portion = portionsById[portionId]
if (portion.millilitersPerAmount) {
const gramsPerMilliliter = weightInGrams / portion.millilitersPerAmount
return millilitersPerAmount * gramsPerMilliliter
}
}
throw new Error()
}
export default getToGramsConversionFactor
================================================
FILE: src/portions/index.ts
================================================
export * from './types'
export * from './usePortionsStore'
export { default as PortionsMenuOrDrawer } from './PortionsMenuOrDrawer'
export { default as formatAmount } from './formatAmount'
export { default as PortionsSelect } from './PortionsSelect'
export { default as useGetAmount } from './useGetAmount'
export { default as getPortionDescription } from './getPortionDescription'
export { default as getIngredientPortionDescription } from './getIngredientPortionDescription'
================================================
FILE: src/portions/types.ts
================================================
type Portion = {
id: string
unit: string
singular: string
description?: string
gramsPerAmount?: number
millilitersPerAmount?: number
}
export type { Portion }
================================================
FILE: src/portions/useGetAmount.ts
================================================
import { Food } from 'foods'
import { useCallbacksMemo } from 'general'
import { usePortions } from 'portions'
import { useCallback } from 'react'
import useGetToGramsConversionFactor from './useGetToGramsConversionFactor'
import getAmountFromPortionToGramsInternal from './getAmountFromPortionsToGrams'
function useGetAmount() {
const { portionsById } = usePortions()
const getToGramsConversionFactor = useGetToGramsConversionFactor()
const getAmountFromPortionToGrams = useCallback(
(amountInGrams: number, portionId: string, food: Food) =>
getAmountFromPortionToGramsInternal(
amountInGrams,
portionId,
food,
portionsById
),
[portionsById]
)
const getAmountFromGramsToPortion = useCallback(
(amountInPortion: number, portionId: string, food: Food) => {
const portion = portionsById[portionId]
const factor = getToGramsConversionFactor(portion, food)
return amountInPortion / factor
},
[portionsById, getToGramsConversionFactor]
)
const getAmountFromPortionToPortion = useCallback(
(
amount: number,
fromPortionId: string,
toPortionId: string,
food: Food
) => {
const amountInGrams = getAmountFromPortionToGrams(
amount,
fromPortionId,
food
)
return getAmountFromGramsToPortion(amountInGrams, toPortionId, food)
},
[getAmountFromPortionToGrams, getAmountFromGramsToPortion]
)
const callbacks = useCallbacksMemo({
getAmountFromPortionToPortion,
getAmountFromPortionToGrams,
getAmountFromGramsToPortion,
})
return callbacks
}
export default useGetAmount
================================================
FILE: src/portions/useGetToGramsConversionFactor.ts
================================================
import { Food } from 'foods'
import { Portion, usePortions } from 'portions'
import { useCallback } from 'react'
import getToGramsConversionFactor from './getToGramsConversionFactor'
function useGetToGramsConversionFactor() {
const { portionsById } = usePortions()
const getToGramsConversionFactorCallback = useCallback(
(portion: Portion, food: Food) =>
getToGramsConversionFactor(portion, food, portionsById),
[portionsById]
)
return getToGramsConversionFactorCallback
}
export default useGetToGramsConversionFactor
================================================
FILE: src/portions/usePortionsStore.ts
================================================
import { makeStoreProvider, useCallbacksMemo } from 'general'
import { useMemo, useState } from 'react'
import { Portion } from './types'
import defaultPortions from './defaultPortions'
type PortionsMap = Record
function usePortionsStore() {
const [portionsById, setPortionsById] = useState(() => {
const initialMap: PortionsMap = {}
for (const portion of defaultPortions) {
initialMap[portion.id] = portion
}
return initialMap
})
const allPortions = useMemo(() => Object.values(portionsById), [portionsById])
const weightBasedPortions = useMemo(
() =>
allPortions.filter(({ gramsPerAmount }) => gramsPerAmount !== undefined),
[allPortions]
)
const volumeBasedPortions = useMemo(
() =>
allPortions.filter(
({ millilitersPerAmount }) => millilitersPerAmount !== undefined
),
[allPortions]
)
const state = useCallbacksMemo({
portionsById,
allPortions,
volumeBasedPortions,
weightBasedPortions,
})
return [state, setPortionsById] as const
}
const [
PortionsStoreProvider,
usePortions,
usePortionsActions,
] = makeStoreProvider(usePortionsStore)
export { PortionsStoreProvider, usePortions, usePortionsActions }
export default usePortionsStore
================================================
FILE: src/react-app-env.d.ts
================================================
///
================================================
FILE: src/reportWebVitals.ts
================================================
import { ReportHandler } from 'web-vitals';
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;
================================================
FILE: src/setupTests.ts
================================================
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';
================================================
FILE: src/stats/AmountInput.tsx
================================================
import { InputProps, Input, Flex } from '@chakra-ui/react'
import { MouseEvent, ReactNode, WheelEvent } from 'react'
import amountAsNumber from 'stats/amountAsNumber'
type Props = {
children?: ReactNode
acceptsFractions?: boolean
} & InputProps
const MAX_AMOUNT_EXCLUDING = 10000
function AmountInput({
name,
children,
acceptsFractions = false,
...rest
}: Props) {
function onMouseDown(event: MouseEvent) {
const input = event.target as HTMLInputElement
if (document.activeElement !== input) {
event.preventDefault()
const length = input.value.length
input.focus()
input.type = 'text'
input.setSelectionRange(length, length)
input.type = 'number'
}
}
function onWheel(event: WheelEvent) {
const target = event.target as HTMLInputElement
target.blur()
}
const numProps = acceptsFractions
? {}
: {
type: 'number',
pattern: '\\d*',
onMouseDown,
onWheel,
}
return (
{
const { value } = event.target
const valueAsNumber = amountAsNumber(value)
if (valueAsNumber >= 0 && valueAsNumber < MAX_AMOUNT_EXCLUDING) {
rest.onChange && rest.onChange(event)
}
}}
/>
{children}
)
}
export default AmountInput
================================================
FILE: src/stats/EnergyStat.tsx
================================================
import Stat, { StatProps } from './Stat'
import { ArrowUpCircle, ArrowDownCircle } from 'react-feather'
import { useSameOrPreviousValue } from 'general'
import StatValueDetail from './StatValueDetail'
type Props = {
energy: number
energyDiff: number
} & StatProps
function EnergyStat({ energy, energyDiff, ...rest }: Props) {
const energyValueDetail = `${Math.abs(energyDiff)}kcal`
const previousOrSameEnergyValueDetail = useSameOrPreviousValue(
energyValueDetail
)
return (
0 ? (
) : (
)
}
/>
) : undefined
}
{...rest}
/>
)
}
export default EnergyStat
================================================
FILE: src/stats/PdfStat.tsx
================================================
import { Text, View, StyleSheet } from '@react-pdf/renderer'
import { Style } from '@react-pdf/types/style'
import getComputedColorFromChakra from 'theme/getComputedColorFromChakra'
import {
getLabelColor,
getValueFontWeight,
getValueTextColor,
isForDiet,
isForEnergy,
isForIngredient,
StatVariant,
} from './statsVariants'
type Props = {
label?: string
value: number
valueDetail?: string
style?: Style
variant: StatVariant
unit?: string
}
function PdfStat({
label,
value,
variant,
valueDetail,
unit = 'g',
style = {},
}: Props) {
return (
{isForDiet(variant) && (
)}
{label && (
{label}
)}
{value}
{isForEnergy(variant) ? 'kcal' : unit}
{valueDetail && {valueDetail}}
)
}
const styles = StyleSheet.create({
root: {
textAlign: 'right',
flex: 1,
},
label: {
fontSize: 10,
marginBottom: 2,
},
unit: {
fontSize: 12,
},
value: {
fontSize: 14,
},
valueDetail: {
marginTop: '2px',
fontSize: 12,
},
line: {
position: 'absolute',
top: '2px',
bottom: '2px',
right: '-10px',
width: '1px',
},
})
export default PdfStat
================================================
FILE: src/stats/PdfStatsLayout.tsx
================================================
import { View, StyleSheet } from '@react-pdf/renderer'
import { ReactElement } from 'react'
type Props = {
nameElement: ReactElement
energyElement: ReactElement
proteinElement: ReactElement
carbsElement: ReactElement
fatElement: ReactElement
}
function PdfStatsLayout({
nameElement,
energyElement,
proteinElement,
carbsElement,
fatElement,
}: Props) {
return (
{nameElement}
{energyElement}
{proteinElement}
{carbsElement}
{fatElement}
)
}
const NAME_WIDTH = '50%'
const MACROS_COUNT = 4
const MACRO_WIDTH = `${(100 - parseInt(NAME_WIDTH, 10)) / MACROS_COUNT}%`
const styles = StyleSheet.create({
root: {
flexDirection: 'row',
},
name: {
width: NAME_WIDTH,
justifyContent: 'center',
},
macro: {
width: MACRO_WIDTH,
marginRight: 12,
},
})
export default PdfStatsLayout
================================================
FILE: src/stats/Stat.tsx
================================================
import { Text, Box, FlexProps } from '@chakra-ui/react'
import { cloneElement, ReactElement } from 'react'
import { RightAligned } from 'layout'
import {
isForDiet,
isForEnergy,
StatVariant,
getValueFontWeight,
getValueTextColor,
getLabelColor,
} from './statsVariants'
type Props = {
value?: number
label?: string
type?: StatVariant
valueDetailElement?: ReactElement
isLarge?: boolean
isDisabled?: boolean
} & FlexProps
function Stat({
value,
label,
type = 'ingredient',
isLarge = false,
valueDetailElement,
isDisabled = false,
...rest
}: Props) {
return (
{isForDiet(type) && (
)}
{label && (
{label}
)}
{value !== undefined && (
{value}
{isForEnergy(type) ? 'kcal' : 'g'}
)}
{valueDetailElement && cloneElement(valueDetailElement, { isLarge })}
)
}
export type { Props as StatProps }
export default Stat
================================================
FILE: src/stats/StatValueDetail.tsx
================================================
import { HStack, Text } from '@chakra-ui/react'
import { Tooltip } from 'general'
import { ReactNode } from 'react'
type Props = {
label: string
tooltipLabel?: string
leftIcon?: ReactNode
isLarge?: boolean
}
function StatValueDetail({
label,
tooltipLabel,
leftIcon,
isLarge = false,
}: Props) {
return (
{leftIcon}
{label}
)
}
export default StatValueDetail
================================================
FILE: src/stats/StatsFormFields/MacrosFormFields.tsx
================================================
import { VStack } from '@chakra-ui/react'
import StatFormField from './StatFormField'
import useGetDailyValuePercent from './useGetDailyValuePercent'
type Props = {
canEdit: boolean
showsEnergyPercentFromFats?: boolean
}
function MacrosFormFields({
canEdit,
showsEnergyPercentFromFats = false,
}: Props) {
const getDailyValuePercent = useGetDailyValuePercent()
return (
{showsEnergyPercentFromFats && (
)}
)
}
export default MacrosFormFields
================================================
FILE: src/stats/StatsFormFields/ReavealButton.tsx
================================================
import { Button, ButtonProps, chakra } from '@chakra-ui/react'
import { ChevronDown, ChevronUp } from 'react-feather'
const ChevronDownStyled = chakra(ChevronDown)
const ChevronUpStyled = chakra(ChevronUp)
type Props = {
isContentShown: boolean
showContentLabel: string
hideContentLabel: string
} & ButtonProps
function RevealButton({
isContentShown,
showContentLabel,
hideContentLabel,
...rest
}: Props) {
return (
)
}
export default RevealButton
================================================
FILE: src/stats/StatsFormFields/StatFormField/ReadOnlyInput.tsx
================================================
import { Text } from '@chakra-ui/react'
import { Controller } from 'react-hook-form'
import { foodCategories } from 'foods-categories'
import { InputType } from './types'
type Props = {
name: string
inputType: InputType
nutritionValueUnit: string
isBold?: boolean
}
function formatNutritionValue(value: string) {
const number = Number(value)
if (Number.isInteger(number)) {
return value
}
return number.toFixed(2)
}
function ReadOnlyInput({
name,
inputType,
nutritionValueUnit,
isBold = false,
}: Props) {
return (
{
let { value } = field
if (inputType === 'foodCategory') {
const foodCategory = foodCategories.find(({ id }) => id === value)
if (foodCategory) {
value = foodCategory.name
}
}
return (
{inputType === 'nutritionValue'
? `${formatNutritionValue(value)}${nutritionValueUnit}`
: value}
)
}}
/>
)
}
export default ReadOnlyInput
================================================
FILE: src/stats/StatsFormFields/StatFormField/index.tsx
================================================
import {
FormControl,
Flex,
FormLabel,
Text,
VStack,
Divider,
FormErrorMessage,
FormControlProps,
Box,
Collapse,
DividerProps,
FormLabelProps,
} from '@chakra-ui/react'
import { useFormError } from 'form'
import { ReactNode, RefObject } from 'react'
import useGetInputElement, { InputType } from './useGetInputElement'
type Props = {
name: string
label?: string
labelElement?: ReactNode
labelDetail?: string
inputType: InputType
nutritionValueUnit?: string
isIdented?: boolean
textInputRef?: RefObject
isReadOnly?: boolean
isEmphasized?: Boolean
isCaption?: boolean
children?: ReactNode
isValueBold?: boolean
dividerProps?: DividerProps
hasDivider?: boolean
dailyValuePercent?: number
formLabelProps?: FormLabelProps
} & FormControlProps
function StatFormField(props: Props) {
const {
name,
label,
inputType,
isIdented = false,
nutritionValueUnit = 'g',
textInputRef,
isReadOnly = false,
isEmphasized = false,
isValueBold = false,
isCaption = false,
isRequired,
children,
labelDetail,
dividerProps = {},
hasDivider = true,
dailyValuePercent,
labelElement,
formLabelProps,
...rest
} = props
const { errorMessage, isInvalid } = useFormError(name)
const inputElement = useGetInputElement({
isInvalid,
name,
inputType,
textInputRef,
isReadOnly,
nutritionValueUnit,
isBold: isValueBold,
})
const labelDetailElement = labelDetail ? (
{labelDetail}
) : null
const isValueNextToLabel = isReadOnly && !(isCaption || isEmphasized)
return (
{hasDivider && }
{label || labelElement}
{isReadOnly && labelDetailElement}
{!isReadOnly && labelDetailElement}
{isValueNextToLabel && {inputElement}}
{!isValueNextToLabel && inputElement}
{dailyValuePercent !== undefined && isValueNextToLabel && (
{`${dailyValuePercent}%`}
)}
{!isReadOnly && inputType === 'nutritionValue' && (
{nutritionValueUnit}
)}
{errorMessage}
{children}
)
}
export type { Props as StatFormFieldProps }
export default StatFormField
================================================
FILE: src/stats/StatsFormFields/StatFormField/types.ts
================================================
type InputType = 'text' | 'nutritionValue' | 'foodCategory'
export type { InputType }
================================================
FILE: src/stats/StatsFormFields/StatFormField/useGetInputElement.tsx
================================================
import { Input, useMergeRefs } from '@chakra-ui/react'
import { cloneElement, ReactElement, RefObject } from 'react'
import { useFormContext, Controller } from 'react-hook-form'
import { FoodCategoriesSelect } from 'foods-categories'
import { InputType } from './types'
import ReadOnlyInput from './ReadOnlyInput'
import { AmountInput } from 'stats'
type Params = {
name: string
inputType: InputType
isInvalid: boolean
textInputRef?: RefObject
nutritionValueUnit: string
isReadOnly: boolean
isBold?: boolean
}
function useGetInputElement({
inputType,
name,
isInvalid,
nutritionValueUnit,
isReadOnly,
textInputRef,
isBold = false,
}: Params) {
const { register } = useFormContext()
let result: ReactElement | null = null
const textInputRegister = register(name)
const finalTextInputRef = useMergeRefs(textInputRegister.ref, textInputRef)
if (isReadOnly) {
result = (
)
} else if (inputType === 'text') {
result = (
)
} else if (inputType === 'foodCategory') {
result = (
)
} else if (inputType === 'nutritionValue') {
result = (
(
)}
/>
)
}
if (!result) {
throw new Error()
}
if (isInvalid) {
return cloneElement(result, {
focusBorderColor: 'red.500',
})
}
return result
}
export type { InputType }
export default useGetInputElement
================================================
FILE: src/stats/StatsFormFields/VitaminsAndMineralsFormFields.tsx
================================================
import { VStack, BoxProps, Divider } from '@chakra-ui/layout'
import { NutritionData, getUnit } from 'stats'
import StatFormField from './StatFormField'
import useGetDailyValuePercent from './useGetDailyValuePercent'
import useGetValue from './useGetValue'
type Props = {
canEdit: boolean
} & BoxProps
type FieldData = {
name: keyof NutritionData
label: string
labelDetail?: string
}
const fieldsData: FieldData[] = [
{ name: 'vitaminA', label: 'Vitamin A' },
{ name: 'vitaminB1', label: 'Vitamin B1', labelDetail: '(thiamin)' },
{ name: 'vitaminB2', label: 'Vitamin B2', labelDetail: '(riboflavin)' },
{ name: 'vitaminB3', label: 'Vitamin B3', labelDetail: '(niacin)' },
{ name: 'vitaminB5', label: 'Vitamin B5', labelDetail: '(pantothenic acid)' },
{ name: 'vitaminB6', label: 'Vitamin B6' },
{ name: 'vitaminB9', label: 'Vitamin B9', labelDetail: '(folate)' },
{ name: 'vitaminB12', label: 'Vitamin B12' },
{ name: 'vitaminC', label: 'Vitamin C' },
{ name: 'vitaminD', label: 'Vitamin D' },
{ name: 'vitaminE', label: 'Vitamin E', labelDetail: '(alpha-tocopherol)' },
{ name: 'vitaminK', label: 'Vitamin K', labelDetail: '(phylloquinone)' },
{ name: 'magnesium', label: 'Magnesium' },
{ name: 'calcium', label: 'Calcium' },
{ name: 'phosphorus', label: 'Phosphorus' },
{ name: 'potassium', label: 'Potassium' },
{ name: 'iron', label: 'Iron' },
{ name: 'selenium', label: 'Selenium' },
{ name: 'zinc', label: 'Zinc' },
{ name: 'manganese', label: 'Manganese' },
{ name: 'copper', label: 'Copper' },
]
function VitaminsAndMinerals({ canEdit, ...rest }: Props) {
const getValue = useGetValue()
const getDailyValuePercent = useGetDailyValuePercent()
const fieldsDataToShow = canEdit
? fieldsData
: fieldsData.filter(({ name }) => getValue(name) > 0)
if (fieldsDataToShow.length === 0) {
return null
}
return (
<>
}
>
{fieldsDataToShow.map(({ name, label, labelDetail }) => (
))}
>
)
}
export default VitaminsAndMinerals
================================================
FILE: src/stats/StatsFormFields/index.tsx
================================================
import { FlexProps, Text, Flex, Box, Divider } from '@chakra-ui/react'
import MacrosFormFields from './MacrosFormFields'
import VitaminsAndMineralsFormFields from './VitaminsAndMineralsFormFields'
type Props = {
canEdit: boolean
showsEnergyPrecentFromFat?: boolean
} & FlexProps
function StatsFormFields({
canEdit,
showsEnergyPrecentFromFat = false,
}: Props) {
return (
{!canEdit && (
<>
% Daily Value *
>
)}
{!canEdit && (
* The % Daily Value (DV) tells you how much a nutrient in a serving
of food contributes to a daily diet. 2000 calories a day is used for
general nutrition advise.{' '}
)}
)
}
export { default as StatFormField } from './StatFormField'
export default StatsFormFields
================================================
FILE: src/stats/StatsFormFields/useGetDailyValuePercent.ts
================================================
import { getDailyValuePercent, NutritionData } from 'stats'
import useGetValue from './useGetValue'
function useGetDailyValuePercent() {
const getValue = useGetValue()
function get(name: keyof NutritionData) {
const value = getValue(name)
return getDailyValuePercent(name, value)
}
return get
}
export default useGetDailyValuePercent
================================================
FILE: src/stats/StatsFormFields/useGetValue.ts
================================================
import { FoodForm } from 'foods'
import { useFormContext } from 'react-hook-form'
import { NutritionData } from 'stats'
function useGetValue() {
const { getValues } = useFormContext()
const values = getValues()
function get(name: keyof NutritionData) {
const valueAsNumber = Number(values[name])
return valueAsNumber
}
return get
}
export default useGetValue
================================================
FILE: src/stats/StatsLayout.tsx
================================================
import { Grid, GridItem, GridProps } from '@chakra-ui/react'
import { useScreenSize, ScreenSize } from 'general'
import { ForwardedRef, ReactElement, forwardRef } from 'react'
type Props = {
nameElement: ReactElement
amountElement?: ReactElement
energyElement: ReactElement
proteinElement: ReactElement
carbsElement: ReactElement
fatElement: ReactElement
menuElement: ReactElement
forwardedRef?: ForwardedRef
prefersAmount?: boolean
} & GridProps
function StatsLayout({
nameElement,
amountElement,
energyElement,
proteinElement,
carbsElement,
fatElement,
menuElement,
forwardedRef,
prefersAmount = false,
...rest
}: Props) {
const screenSize = useScreenSize()
if (screenSize >= ScreenSize.Medium) {
return (
{amountElement && {amountElement}}
{nameElement}
{energyElement}
{proteinElement}
{carbsElement}
{fatElement}
{menuElement}
)
}
if (screenSize === 1) {
return (
{amountElement && {amountElement}}
{nameElement}
{energyElement}
{menuElement}
)
}
return (
{prefersAmount && {amountElement}}
{nameElement}
{!prefersAmount && {energyElement}}
{menuElement}
)
}
export default forwardRef((props, ref) => (
))
================================================
FILE: src/stats/amountAsNumber.ts
================================================
import numericQuantity from 'numeric-quantity'
function amountAsNumber(amount: string) {
if (amount === '') {
return 0
}
const t = parseInt(amount, 10)
if (Number.isNaN(t)) {
return 0
}
const q = numericQuantity(amount)
if (Number.isNaN(q)) {
return t
}
return q
}
export default amountAsNumber
================================================
FILE: src/stats/calculations/aggregateStats.ts
================================================
import { objectFromNutritionDataKeys, NUTRITION_STATS_KEYS } from 'stats'
import { Stats } from '../types'
function sumStats(stats: Stats[]): Stats {
const result: Stats = {
amountInGrams: 0,
...objectFromNutritionDataKeys(key => 0),
}
for (const stat of stats) {
result.amountInGrams += stat.amountInGrams
for (const key of NUTRITION_STATS_KEYS) {
result[key] += stat[key]
}
}
return result
}
function avgStats(
stats: Stats[],
round: (x: number) => number = Math.round
): Stats {
const result = sumStats(stats)
let key: keyof typeof result
for (key in result) {
result[key] = round(result[key] / stats.length)
}
return result
}
export { sumStats, avgStats }
================================================
FILE: src/stats/calculations/getDailyValuePercent.ts
================================================
import { NutritionData } from 'stats'
type DailyValuesRecord = Partial>
// From: https://www.fda.gov/food/new-nutrition-facts-label/daily-value-new-nutrition-and-supplement-facts-labels
const DAILY_VALUES_RECORD: DailyValuesRecord = {
calcium: 1300,
fiber: 28,
magnesium: 420,
manganese: 2.3,
phosphorus: 1250,
potassium: 4700,
vitaminA: 900,
vitaminB1: 1.5,
vitaminB2: 1.3,
vitaminB5: 5,
vitaminB6: 1.7,
vitaminB12: 2.4,
vitaminC: 90,
vitaminD: 20,
vitaminE: 15,
vitaminK: 120,
copper: 0.9,
selenium: 55,
sodium: 2300,
cholesterol: 300,
iron: 18,
saturatedFat: 20,
choline: 550,
}
function getDailyValuePercent(name: keyof NutritionData, value: number) {
const dailyValue = DAILY_VALUES_RECORD[name]
if (dailyValue === undefined) {
return undefined
}
return Math.round((100 * value) / dailyValue)
}
export default getDailyValuePercent
================================================
FILE: src/stats/calculations/getEnergiesEstimates.ts
================================================
import { Stats } from 'stats/types'
const CALORIES_PER_GRAM_PROTEIN = 4
const CALORIES_PER_GRAM_CARBS = 4
const CALORIES_PER_GRAM_FAT = 9
function getProteinEnergyEstimate(gramsProtein: number) {
return gramsProtein * CALORIES_PER_GRAM_PROTEIN
}
function getCarbsEnergyEstimate(gramsCarbs: number) {
return gramsCarbs * CALORIES_PER_GRAM_CARBS
}
function getFatEnergyEstimate(gramsFat: number) {
return gramsFat * CALORIES_PER_GRAM_FAT
}
function getStatsEnergiesEstimates(stats: Stats) {
const { protein, carbs, fat } = stats
const proteinEnergyEstimate = getProteinEnergyEstimate(protein)
const carbsEnergyEstimate = getCarbsEnergyEstimate(carbs)
const fatEnergyEstimate = getFatEnergyEstimate(fat)
const energyEstimate =
proteinEnergyEstimate + carbsEnergyEstimate + fatEnergyEstimate
return {
energyEstimate,
proteinEnergyEstimate,
carbsEnergyEstimate,
fatEnergyEstimate,
}
}
export {
getProteinEnergyEstimate,
getCarbsEnergyEstimate,
getFatEnergyEstimate,
getStatsEnergiesEstimates,
}
================================================
FILE: src/stats/calculations/getMacrosPercents.ts
================================================
import { Stats } from '../types'
import { getStatsEnergiesEstimates } from './getEnergiesEstimates'
type MacrosPercents = {
proteinPercent: number
carbsPercent: number
fatPercent: number
}
function getMacroEnergyPercent(energyFromMacro: number, energyTotal: number) {
return energyFromMacro === 0 ? 0 : (energyFromMacro / energyTotal) * 100
}
function getMacrosPercents(stats: Stats): MacrosPercents {
const {
energyEstimate,
proteinEnergyEstimate,
carbsEnergyEstimate,
fatEnergyEstimate,
} = getStatsEnergiesEstimates(stats)
return {
proteinPercent: getMacroEnergyPercent(
proteinEnergyEstimate,
energyEstimate
),
carbsPercent: getMacroEnergyPercent(carbsEnergyEstimate, energyEstimate),
fatPercent: getMacroEnergyPercent(fatEnergyEstimate, energyEstimate),
}
}
export type { MacrosPercents }
export { getMacroEnergyPercent }
export default getMacrosPercents
================================================
FILE: src/stats/calculations/getStatsTree.ts
================================================
import { sumStats, avgStats } from './aggregateStats'
import { Stats } from '../types'
type StatsTree = {
id: string
stats: Stats
avg?: Stats
subtrees: StatsTree[]
}
type Params = {
id: string
subtrees: StatsTree[]
calculateAvg?: boolean
}
function getStatsTree({ id, subtrees, calculateAvg = false }: Params) {
const subtreesStats = subtrees.map(({ stats }) => stats)
const result: StatsTree = {
id,
stats: sumStats(subtreesStats),
subtrees,
}
if (calculateAvg) {
result.avg = avgStats(subtreesStats)
}
return result
}
export type { StatsTree }
export default getStatsTree
================================================
FILE: src/stats/calculations/index.ts
================================================
export { default as roundMacrosPercents } from './roundMacrosPercents'
export { default as getMacrosPercents } from './getMacrosPercents'
export * from './getMacrosPercents'
export * from './getStatsTree'
export { default as getStatsTree } from './getStatsTree'
export * from './aggregateStats'
export * from './getEnergiesEstimates'
export { default as getDailyValuePercent } from './getDailyValuePercent'
================================================
FILE: src/stats/calculations/roundMacrosPercents.ts
================================================
import { MacrosPercents } from './getMacrosPercents'
type RoundedMacroPercent = {
value: number
type: 'protein' | 'fat' | 'carbs'
}
function getDiff(macroPercents: MacrosPercents) {
return (
100 -
Object.values(macroPercents)
.map(percent => Math.floor(percent))
.reduce((sumSoFar, percent) => percent + sumSoFar, 0)
)
}
function getRoundedMacroPercents(
macroPercents: MacrosPercents,
diff: number
): RoundedMacroPercent[] {
const { proteinPercent, carbsPercent, fatPercent } = macroPercents
const initialRoundedMacroPercents: RoundedMacroPercent[] = [
{ value: proteinPercent, type: 'protein' },
{ value: carbsPercent, type: 'carbs' },
{ value: fatPercent, type: 'fat' },
]
return initialRoundedMacroPercents
.sort(({ value }) => value - Math.floor(value))
.map(({ value, type }, index) =>
index < diff
? {
type,
value: Math.floor(value) + 1,
}
: {
type,
value: Math.floor(value),
}
)
}
function getMacrosPercents(
roundedMacroPercents: RoundedMacroPercent[]
): MacrosPercents {
let roundedProteinPercent = 0
let roundedCarbsPercent = 0
let roundedFatPercent = 0
for (const { type, value } of roundedMacroPercents) {
if (type === 'protein') {
roundedProteinPercent = value
} else if (type === 'carbs') {
roundedCarbsPercent = value
} else {
roundedFatPercent = value
}
}
return {
proteinPercent: roundedProteinPercent,
carbsPercent: roundedCarbsPercent,
fatPercent: roundedFatPercent,
}
}
function roundMacrosPercents(macroPercents: MacrosPercents): MacrosPercents {
const { proteinPercent, carbsPercent, fatPercent } = macroPercents
if (proteinPercent === 0 && carbsPercent === 0 && fatPercent === 0) {
return macroPercents
}
const diff = getDiff(macroPercents)
const roundedMacroPercents = getRoundedMacroPercents(macroPercents, diff)
return getMacrosPercents(roundedMacroPercents)
}
export default roundMacrosPercents
================================================
FILE: src/stats/getUnit.ts
================================================
import { NutritionData } from 'stats'
type Unit = 'mcg' | 'mg' | 'g'
type UnitsRecord = Record
const unitsRecord: UnitsRecord = {
energy: 'g',
fat: 'g',
saturatedFat: 'g',
monounsaturatedFat: 'g',
polyunsaturatedFat: 'g',
carbs: 'g',
sugar: 'g',
fiber: 'g',
protein: 'g',
sodium: 'mg',
cholesterol: 'mg',
vitaminA: 'mcg',
vitaminB1: 'mg',
vitaminB2: 'mg',
vitaminB3: 'mg',
vitaminB5: 'mg',
vitaminB6: 'mg',
vitaminB9: 'mcg',
vitaminB12: 'mcg',
vitaminC: 'mg',
vitaminD: 'mcg',
vitaminE: 'mg',
vitaminK: 'mcg',
magnesium: 'mg',
calcium: 'mg',
phosphorus: 'mg',
potassium: 'mg',
iron: 'mg',
selenium: 'mcg',
zinc: 'mcg',
manganese: 'mg',
copper: 'mg',
choline: 'g',
}
function getUnit(name: keyof NutritionData) {
const unit = unitsRecord[name]
return unit
}
export default getUnit
================================================
FILE: src/stats/index.ts
================================================
export * from './types'
export * from './useMealsStatsStore'
export { default as useUpdateMealStats } from './useUpdateMealStats'
export { default as useVariantStats } from './useVariantStats'
export * from './calculations'
export { default as Stat } from './Stat'
export { default as StatsLayout } from './StatsLayout'
export { default as objectFromNutritionDataKeys } from './objectFromNutritionDataKeys'
export * from './objectFromNutritionDataKeys'
export { default as StatsFormFields } from './StatsFormFields'
export * from './StatsFormFields'
export { default as AmountInput } from './AmountInput'
export { default as EnergyStat } from './EnergyStat'
export { default as getUnit } from './getUnit'
export { default as StatValueDetail } from './StatValueDetail'
================================================
FILE: src/stats/objectFromNutritionDataKeys.ts
================================================
import { NutritionData } from './types'
type MappedNutritionData = { [k in keyof NutritionData]: T }
const NUTRITION_STATS_KEYS: (keyof NutritionData)[] = [
'protein',
'carbs',
'fat',
'saturatedFat',
'monounsaturatedFat',
'polyunsaturatedFat',
'energy',
'sugar',
'fiber',
'sodium',
'cholesterol',
'vitaminA',
'vitaminD',
'vitaminE',
'vitaminK',
'vitaminB1',
'vitaminB12',
'vitaminB2',
'vitaminB5',
'vitaminB6',
'vitaminB3',
'vitaminB9',
'vitaminC',
'vitaminD',
'vitaminE',
'vitaminK',
'magnesium',
'calcium',
'phosphorus',
'potassium',
'iron',
'selenium',
'zinc',
'manganese',
'copper',
'choline',
]
function objectFromNutritionDataKeys(
f: (key: keyof NutritionData) => T
): MappedNutritionData {
const entries = NUTRITION_STATS_KEYS.map(key => {
return [key, f(key)]
})
return Object.fromEntries(entries)
}
export { NUTRITION_STATS_KEYS }
export type { MappedNutritionData }
export default objectFromNutritionDataKeys
================================================
FILE: src/stats/statsVariants.ts
================================================
type StatVariant =
| 'ingredient'
| 'ingredientAmount'
| 'ingredientEnergy'
| 'meal'
| 'mealEnergy'
| 'diet'
| 'dietEnergy'
function isForDiet(statVariant: StatVariant) {
return statVariant.startsWith('diet')
}
function isForEnergy(statVariant: StatVariant) {
return statVariant.endsWith('Energy')
}
function isForIngredient(statVaraint: StatVariant) {
return statVaraint.startsWith('ingredient')
}
function isForMeal(statVaraint: StatVariant) {
return statVaraint.startsWith('meal')
}
function getValueTextColor(statVariant: StatVariant) {
if (isForIngredient(statVariant)) {
return 'gray.500'
}
return 'gray.800'
}
function getValueFontWeight(statVariant: StatVariant) {
if (statVariant === 'dietEnergy') {
return 'bold'
}
if (statVariant === 'diet' || statVariant === 'mealEnergy') {
return 'medium'
}
return undefined
}
function getLabelColor(statVariant: StatVariant) {
if (isForDiet(statVariant)) {
return 'gray.800'
}
return 'gray.500'
}
export {
getValueTextColor,
getValueFontWeight,
isForDiet,
isForEnergy,
isForIngredient,
isForMeal,
getLabelColor,
}
export type { StatVariant }
================================================
FILE: src/stats/types.ts
================================================
type NutritionData = {
energy: number
fat: number
saturatedFat: number
monounsaturatedFat: number
polyunsaturatedFat: number
carbs: number
sugar: number
fiber: number
protein: number
sodium: number
cholesterol: number
vitaminA: number
vitaminB1: number
vitaminB2: number
vitaminB3: number
vitaminB5: number
vitaminB6: number
vitaminB9: number
vitaminB12: number
vitaminC: number
vitaminD: number
vitaminE: number
vitaminK: number
magnesium: number
calcium: number
phosphorus: number
potassium: number
iron: number
selenium: number
zinc: number
manganese: number
copper: number
choline: number
}
type Stats = {
amountInGrams: number
} & NutritionData
export type { Stats, NutritionData }
================================================
FILE: src/stats/useMealsStatsStore.ts
================================================
import { Stats } from './types'
import { useState, useCallback } from 'react'
import produce from 'immer'
import { makeStoreProvider, useCallbacksMemo } from 'general'
type MealsStats = Record | undefined>
function useMealsStatsStore() {
const [mealsStats, setMealsStats] = useState({})
const setMealStats = useCallback(
(variantFormFieldId: string, index: number, stats: Stats) =>
setMealsStats(
produce(draftMealsStats => {
let variantMealsStats = draftMealsStats[variantFormFieldId]
if (!variantMealsStats) {
variantMealsStats = {}
draftMealsStats[variantFormFieldId] = variantMealsStats
}
variantMealsStats[index] = stats
})
),
[]
)
const deleteMealStats = useCallback(
(variantFormFieldId: string, index: number) =>
setMealsStats(
produce(draftMealsStats => {
let variantMealsStats = draftMealsStats[variantFormFieldId]
if (variantMealsStats) {
delete variantMealsStats[index]
}
})
),
[]
)
const actions = useCallbacksMemo({ setMealStats, deleteMealStats })
return [mealsStats, actions] as const
}
const [
MealsStatsStoreProvider,
useMealsStats,
useMealsStatsActions,
] = makeStoreProvider(useMealsStatsStore)
export { MealsStatsStoreProvider, useMealsStatsActions, useMealsStats }
export default useMealsStatsStore
================================================
FILE: src/stats/useUpdateMealStats.ts
================================================
import { Stats } from './types'
import { useEffect } from 'react'
import { useMealsStatsActions } from './useMealsStatsStore'
type Params = {
stats: Stats
selectedVariantFormFieldId: string
index: number
}
function useUpdateMealStats({
stats,
selectedVariantFormFieldId,
index,
}: Params) {
const mealsStatsActions = useMealsStatsActions()
useEffect(() => {
mealsStatsActions.setMealStats(selectedVariantFormFieldId, index, stats)
return () => {
mealsStatsActions.deleteMealStats(selectedVariantFormFieldId, index)
}
}, [stats, mealsStatsActions, index, selectedVariantFormFieldId])
}
export default useUpdateMealStats
================================================
FILE: src/stats/useVariantStats.ts
================================================
import { useMemo, useRef } from 'react'
import { getMacrosPercents, roundMacrosPercents } from './calculations'
import { sumStats } from 'stats'
import { useMealsStats } from './useMealsStatsStore'
import { useDietForm } from 'diets'
type Params = {
variantFormFieldId: string
}
function useVariantStats({ variantFormFieldId }: Params) {
const mealsStats = useMealsStats()
const dietForm = useDietForm()
const energyCacheRef = useRef>({})
const variantForm = dietForm.variantsForms.find(
({ fieldId }) => fieldId === variantFormFieldId
)
const shouldSetEnergyToZero =
variantForm && variantForm.mealsForms.length === 0
const variantStats = useMemo(() => {
const mealsStatsForVariant = mealsStats[variantFormFieldId]
const finalStats = mealsStatsForVariant
? Object.values(mealsStatsForVariant)
: []
const statsSum = sumStats(finalStats)
if (shouldSetEnergyToZero) {
energyCacheRef.current[variantFormFieldId] = 0
} else if (
mealsStatsForVariant &&
energyCacheRef.current[variantFormFieldId] === undefined
) {
energyCacheRef.current[variantFormFieldId] = statsSum.energy
}
return statsSum
}, [mealsStats, variantFormFieldId, shouldSetEnergyToZero])
const { proteinPercent, carbsPercent, fatPercent } = useMemo(() => {
return roundMacrosPercents(getMacrosPercents(variantStats))
}, [variantStats])
const cachedEnergy = energyCacheRef.current[variantFormFieldId]
const energyDiff =
cachedEnergy !== undefined && cachedEnergy > 0
? variantStats.energy - cachedEnergy
: 0
return {
variantStats,
proteinPercent,
carbsPercent,
fatPercent,
energyDiff,
}
}
export default useVariantStats
================================================
FILE: src/theme/colors.ts
================================================
const colors = {
custom: {
'50': '#74CFD1',
'500': '#74CFD1',
'600': '#38a8aa',
},
}
export default colors
================================================
FILE: src/theme/components/Alert.ts
================================================
const Alert = {
variants: {
subtle: {
container: {
bg: 'gray.100',
borderRadius: 6,
},
},
},
}
export default Alert
================================================
FILE: src/theme/components/Button.ts
================================================
const Button = {}
export default Button
================================================
FILE: src/theme/components/Divider.ts
================================================
const Divider = {
sizes: {
md: {
borderBottomWidth: '8px',
},
lg: {
borderBottomWidth: '12px',
},
},
}
export default Divider
================================================
FILE: src/theme/components/Input.ts
================================================
const Input = {
defaultProps: {
focusBorderColor: 'teal.400',
},
}
export default Input
================================================
FILE: src/theme/components/Textarea.ts
================================================
const Textarea = {
defaultProps: {
focusBorderColor: 'teal.400',
},
}
export default Textarea
================================================
FILE: src/theme/components/index.ts
================================================
export { default as Input } from './Input'
export { default as Button } from './Button'
export { default as Divider } from './Divider'
export { default as Textarea } from './Textarea'
export { default as Alert } from './Alert'
================================================
FILE: src/theme/getComputedColorFromChakra.ts
================================================
/* React-pdf does not have access to the Chakra context so we
use the css variables to get the actual color values*/
const map: Record = {
'gray.50': '#F7FAFC',
'teal.500': '#319795',
'teal.400': '#38B2AC',
'gray.400': '#A0AEC0',
'gray.600': '#4A5568',
'gray.500': '#718096',
'gray.100': '#EDF2F7',
'gray.200': '#E2E8F0',
'gray.300': '#CBD5E0',
'teal.600': '#2C7A7B',
}
function getComputedColorFromChakra(chakraColor: string) {
return map[chakraColor]
}
export default getComputedColorFromChakra
================================================
FILE: src/theme/index.ts
================================================
import { extendTheme } from '@chakra-ui/react'
import styles from './styles'
import colors from './colors'
import { Input, Button, Divider, Textarea, Alert } from './components'
const theme = extendTheme({
styles,
colors,
config: { initialColorMode: 'light', useSystemColorMode: false },
components: {
Input,
Button,
Divider,
Textarea,
Alert,
},
})
export { default as getComputedColorFromChakra } from './getComputedColorFromChakra'
export default theme
================================================
FILE: src/theme/styles.ts
================================================
const styles = {
global: {
body: {
overflowX: 'hidden',
fontFamily: 'Roboto',
background: 'gray.50',
},
'.js-focus-visible :focus:not([data-focus-visible-added])': {
outline: 'none',
boxShadow: 'none',
},
'.rc-menu__item--hover': {
backgroundColor: '#EDF2F7',
},
'.rc-menu__item--active': {
color: 'black',
backgroundColor: '#E2E8F0',
},
},
}
export default styles
================================================
FILE: src/undoRedo/UndoRedoButtons/RedoButton.tsx
================================================
import { chakra, IconButton, Button } from '@chakra-ui/react'
import { useDietFormVersionsActions, useDietFormVersions } from 'undoRedo'
import { RotateCw } from 'react-feather'
import {
getCtrlKeyName,
TooltipCommandLabel,
Tooltip,
useScreenSize,
ScreenSize,
} from 'general'
const RotateCwStyled = chakra(RotateCw)
const ctrlKeyName = getCtrlKeyName()
function RedoButton() {
const { redo } = useDietFormVersionsActions()
const { canRedo } = useDietFormVersions()
const screenSize = useScreenSize()
if (screenSize >= ScreenSize.Medium) {
return (
}
>
}
isDisabled={!canRedo}
onClick={() => redo()}
>
Redo
)
}
return (
}
isDisabled={!canRedo}
onClick={() => redo()}
/>
)
}
export default RedoButton
================================================
FILE: src/undoRedo/UndoRedoButtons/UndoButton.tsx
================================================
import { chakra, IconButton, Button } from '@chakra-ui/react'
import { useDietFormVersionsActions, useDietFormVersions } from 'undoRedo'
import { RotateCcw } from 'react-feather'
import {
getCtrlKeyName,
TooltipCommandLabel,
Tooltip,
useScreenSize,
ScreenSize,
} from 'general'
const RotateCcwStyled = chakra(RotateCcw)
const ctrlKeyName = getCtrlKeyName()
function UndoButton() {
const { undo } = useDietFormVersionsActions()
const { canUndo } = useDietFormVersions()
const screenSize = useScreenSize()
if (screenSize >= ScreenSize.Medium) {
return (
}
>
}
isDisabled={!canUndo}
onClick={() => undo()}
>
Undo
)
}
return (
}
isDisabled={!canUndo}
onClick={() => undo()}
/>
)
}
export default UndoButton
================================================
FILE: src/undoRedo/UndoRedoButtons/index.tsx
================================================
import { ButtonGroup } from '@chakra-ui/react'
import UndoButton from './UndoButton'
import RedoButton from './RedoButton'
function UndoRedoButtons() {
return (
)
}
export default UndoRedoButtons
================================================
FILE: src/undoRedo/appLocation.ts
================================================
import { DietForm } from 'diets'
import { RefObject } from 'react'
type AppLocation = {
scrollTop: number
scrollLeft: number
variantIndex: number
}
type Params = {
horizontalScrollRef: RefObject
dietForm: DietForm
}
function getAppLocation({
horizontalScrollRef,
dietForm,
}: Params): AppLocation {
return {
scrollTop: window.scrollY,
scrollLeft: horizontalScrollRef.current
? horizontalScrollRef.current.scrollLeft
: 0,
variantIndex: dietForm.selectedVariantFormIndex,
}
}
export type { AppLocation }
export default getAppLocation
================================================
FILE: src/undoRedo/deltasStack.ts
================================================
import { Delta } from 'jsondiffpatch'
import { AppLocation } from './appLocation'
type DeltaNode = {
delta: Delta
appLocation: AppLocation
nextNode?: DeltaNode
prevNode?: DeltaNode
}
const MAX_SIZE = 100
class DeltasStack {
startNode?: DeltaNode = undefined
pointerNode?: DeltaNode = undefined
size: number = 0
canUnpatch: boolean = false
canPatch: boolean = false
getNextNodeToUnpatch(): DeltaNode | null {
if (!this.canUnpatch) {
return null
}
if (!this.pointerNode) {
this.pointerNode = this.startNode
} else {
this.pointerNode = this.pointerNode.nextNode
}
if (this.pointerNode) {
this.canUnpatch = this.pointerNode.nextNode !== undefined
this.canPatch = true
// jsondiffpatch sometimes modifies this delta for some reason
return this.pointerNode
}
this.canUnpatch = false
return null
}
getNextNodeToPatch(): DeltaNode | null {
if (this.pointerNode) {
const result = this.pointerNode
this.pointerNode = this.pointerNode.prevNode
this.canPatch = this.pointerNode !== undefined
this.canUnpatch = true
return result
}
return null
}
keepOnlyLast(n: number) {
let node: DeltaNode | undefined = this.startNode
let index = 0
while (node) {
if (index + 1 === n) {
this.size = n
node.nextNode = undefined
break
}
node = node.nextNode
index++
}
}
push(delta: Delta, appLocation: AppLocation) {
if (this.pointerNode) {
this.startNode = this.pointerNode.nextNode
this.pointerNode = undefined
}
const node: DeltaNode = {
delta,
appLocation,
}
if (!this.startNode) {
this.startNode = node
} else {
node.nextNode = this.startNode
this.startNode.prevNode = node
this.startNode = node
}
this.size++
if (this.size >= MAX_SIZE) {
this.keepOnlyLast(Math.floor(MAX_SIZE / 2))
}
this.canUnpatch = true
this.canPatch = false
}
}
export default DeltasStack
================================================
FILE: src/undoRedo/index.ts
================================================
export * from './useDietFormVersionsStore'
export { default as useKeyboard } from './useKeyboard'
export { default as UndoRedoButtons } from './UndoRedoButtons'
export * from './appLocation'
================================================
FILE: src/undoRedo/useDietFormVersionsStore.ts
================================================
import { useCallback, useRef, useState, RefObject, useEffect } from 'react'
import * as jsondiffpatch from 'jsondiffpatch'
import { Delta } from 'jsondiffpatch'
import DeltasStack from './deltasStack'
import { makeStoreProvider, useCallbacksMemo, deepCopy } from 'general'
import { DietForm } from 'diets'
import getAppLocation, { AppLocation } from './appLocation'
type Params = {
form: DietForm
horizontalScrollRef: RefObject
onUndo: (form: DietForm, appLocation: AppLocation) => void
onRedo: (form: DietForm, appLocation: AppLocation) => void
}
const patcher = jsondiffpatch.create({
objectHash: (item: any) => item.fieldId,
})
const TIMEOUT_IN_MS = 200
type UndoRedoState = {
canUndo: boolean
canRedo: boolean
}
function shouldSaveDelta(delta: Delta) {
const onlySelectedFormIndexChanged =
Object.keys(delta).length === 1 &&
delta.selectedVariantFormIndex !== undefined
return false === onlySelectedFormIndexChanged
}
function useDietFormVersionsStore({
form,
horizontalScrollRef,
onUndo,
onRedo,
}: Params) {
const deltasStackRef = useRef(new DeltasStack())
const lastFormRef = useRef