@jeremyckahn/farmhand 1.23.2 → 1.23.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/README.md +1 -0
  2. package/dist/assets/{index-DNPchtK9.js → index-Dihg7UqQ.js} +15 -15
  3. package/dist/assets/{index-DNPchtK9.js.map → index-Dihg7UqQ.js.map} +1 -1
  4. package/dist/index.html +1 -1
  5. package/dist/service-worker.js +1 -1
  6. package/dist/service-worker.js.map +1 -1
  7. package/package.json +4 -5
  8. package/src/common/services/randomNumber.test.ts +61 -1
  9. package/src/common/services/randomNumber.ts +36 -1
  10. package/src/common/utils.ts +22 -13
  11. package/src/components/AccountingView/AccountingView.tsx +4 -12
  12. package/src/components/Achievement/Achievement.tsx +0 -13
  13. package/src/components/AchievementsView/AchievementsView.tsx +2 -7
  14. package/src/components/AnimatedNumber/AnimatedNumber.tsx +0 -6
  15. package/src/components/AppBar/AppBar.tsx +0 -10
  16. package/src/components/Cellar/Cellar.tsx +0 -2
  17. package/src/components/Cellar/CellarInventoryTabPanel.tsx +0 -6
  18. package/src/components/Cellar/FermentationTabPanel.tsx +0 -6
  19. package/src/components/Cellar/Keg.tsx +0 -5
  20. package/src/components/Cellar/TabPanel/index.tsx +0 -7
  21. package/src/components/Cellar/WinemakingTabPanel.tsx +0 -6
  22. package/src/components/ContextPane/ContextPane.tsx +0 -6
  23. package/src/components/CowCard/Bloodline/Bloodline.tsx +0 -5
  24. package/src/components/CowCard/CowCard.tsx +0 -26
  25. package/src/components/CowCard/Subheader/Subheader.tsx +11 -26
  26. package/src/components/CowPen/CowPen.tsx +4 -15
  27. package/src/components/CowPenContextMenu/CowPenContextMenu.tsx +0 -16
  28. package/src/components/CowPenContextMenu/TabPanel/index.tsx +0 -7
  29. package/src/components/Farmhand/Farmhand.context.tsx +4 -3
  30. package/src/components/Farmhand/Farmhand.tsx +4 -11
  31. package/src/components/Farmhand/FarmhandReducers.tsx +1 -2
  32. package/src/components/Farmhand/FarmhandService.test.ts +6 -9
  33. package/src/components/Farmhand/hooks/useFarmhandDayAdvancement.ts +2 -6
  34. package/src/components/Farmhand/hooks/useFarmhandNetwork.test.ts +2 -2
  35. package/src/components/Farmhand/hooks/useFarmhandNetwork.ts +15 -31
  36. package/src/components/Farmhand/useFarmhand.test.ts +7 -5
  37. package/src/components/Farmhand/useFarmhand.ts +12 -13
  38. package/src/components/FermentationRecipeList/FermentationRecipe.tsx +0 -5
  39. package/src/components/FermentationRecipeList/FermentationRecipeList.test.tsx +10 -11
  40. package/src/components/FermentationRecipeList/FermentationRecipeList.tsx +2 -3
  41. package/src/components/Field/Field.tsx +13 -48
  42. package/src/components/Forest/Forest.tsx +10 -7
  43. package/src/components/ForestPlot/ForestPlot.tsx +5 -5
  44. package/src/components/ForestQuickSelect/ForestQuickSelect.tsx +0 -12
  45. package/src/components/Home/Home.tsx +0 -6
  46. package/src/components/Home/SnowBackground.tsx +1 -1
  47. package/src/components/IngredientsList/IngredientsList.tsx +0 -7
  48. package/src/components/Inventory/Inventory.test.tsx +4 -4
  49. package/src/components/Inventory/Inventory.tsx +3 -11
  50. package/src/components/Item/Item.tsx +0 -21
  51. package/src/components/ItemList/ItemList.tsx +4 -11
  52. package/src/components/KeybindingsView/KeybindingsView.tsx +0 -2
  53. package/src/components/LogView/LogView.tsx +0 -6
  54. package/src/components/Navigation/DayAndProgressContainer.tsx +0 -7
  55. package/src/components/Navigation/Navigation.tsx +0 -23
  56. package/src/components/NotificationSystem/NotificationSystem.test.tsx +4 -1
  57. package/src/components/NotificationSystem/NotificationSystem.tsx +5 -12
  58. package/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.test.tsx +2 -2
  59. package/src/components/OnlinePeersView/OnlinePeer/OnlinePeer.tsx +0 -11
  60. package/src/components/OnlinePeersView/OnlinePeersView.tsx +0 -10
  61. package/src/components/Plot/Plot.tsx +3 -3
  62. package/src/components/PriceEventView/PriceEventView.tsx +0 -6
  63. package/src/components/ProgressBar/ProgressBar.tsx +0 -5
  64. package/src/components/QuantityInput/QuantityInput.tsx +0 -9
  65. package/src/components/QuickSelect/QuickSelect.tsx +0 -10
  66. package/src/components/Recipe/Recipe.tsx +0 -9
  67. package/src/components/RecipeList/RecipeList.tsx +0 -6
  68. package/src/components/SearchBar/SearchBar.tsx +0 -6
  69. package/src/components/SettingsView/RandomSeedInput.test.tsx +2 -4
  70. package/src/components/SettingsView/RandomSeedInput.tsx +5 -8
  71. package/src/components/SettingsView/SettingsView.test.tsx +21 -0
  72. package/src/components/SettingsView/SettingsView.tsx +24 -16
  73. package/src/components/Shop/Shop.tsx +0 -20
  74. package/src/components/Shop/TabPanel/index.tsx +0 -7
  75. package/src/components/Stage/Stage.tsx +11 -20
  76. package/src/components/StatsView/StatsView.tsx +0 -15
  77. package/src/components/TierPurchase/TierPurchase.tsx +0 -12
  78. package/src/components/Toolbelt/Toolbelt.tsx +5 -10
  79. package/src/components/UpgradePurchase/UpgradePurchase.tsx +0 -10
  80. package/src/components/WineRecipeList/WineRecipe.test.tsx +2 -2
  81. package/src/components/WineRecipeList/WineRecipe.tsx +0 -5
  82. package/src/components/WineRecipeList/WineRecipeList.tsx +2 -3
  83. package/src/components/Workshop/ForgeTabPanel.tsx +0 -8
  84. package/src/components/Workshop/KitchenTabPanel.tsx +0 -7
  85. package/src/components/Workshop/RecyclingTabPanel.tsx +0 -7
  86. package/src/components/Workshop/TabPanel/index.tsx +0 -7
  87. package/src/components/Workshop/WoodChipperTabPanel.tsx +0 -7
  88. package/src/components/Workshop/Workshop.tsx +0 -9
  89. package/src/components/Workshop/getUpgradesAvailable.ts +1 -1
  90. package/src/constants.ts +18 -13
  91. package/src/data/crops/grape.ts +13 -15
  92. package/src/data/maps.test.ts +3 -4
  93. package/src/data/maps.ts +27 -29
  94. package/src/enums.ts +47 -19
  95. package/src/factories/OreFactory.ts +2 -1
  96. package/src/farmhand.d.ts +2 -3
  97. package/src/game-logic/reducers/applyPrecipitation.ts +4 -4
  98. package/src/game-logic/reducers/generatePriceEvents.ts +6 -3
  99. package/src/game-logic/reducers/harvestForestPlot.ts +1 -2
  100. package/src/game-logic/reducers/makeFermentationRecipe.ts +2 -3
  101. package/src/game-logic/reducers/minePlot.test.ts +2 -2
  102. package/src/game-logic/reducers/minePlot.ts +1 -1
  103. package/src/game-logic/reducers/processCowFertilizerProduction.test.ts +16 -14
  104. package/src/game-logic/reducers/processFeedingCows.test.ts +2 -5
  105. package/src/game-logic/reducers/purchaseCow.ts +2 -7
  106. package/src/game-logic/reducers/updateAchievements.ts +1 -1
  107. package/src/game-logic/reducers/updateFinancialRecords.test.ts +21 -25
  108. package/src/game-logic/reducers/updateFinancialRecords.ts +2 -5
  109. package/src/game-logic/reducers/updateInventoryRecordsForNextDay.test.ts +12 -14
  110. package/src/handlers/ui-events.test.ts +44 -42
  111. package/src/handlers/ui-events.tsx +10 -0
  112. package/src/hooks/usePrefersReducedMotion.ts +10 -6
  113. package/src/mui-theme.ts +4 -3
  114. package/src/scripts/generate-crop-table.ts +3 -2
  115. package/src/styles/sx.ts +29 -25
  116. package/src/test-utils/index.ts +1 -0
  117. package/src/utils/chooseRandom.ts +4 -1
  118. package/src/utils/chooseRandomIndex.ts +6 -2
  119. package/src/utils/getCowImage.ts +22 -16
  120. package/src/utils/getMaxYieldOfFermentationRecipe.ts +2 -2
  121. package/src/utils/getPeerMetadata.ts +1 -1
  122. package/src/utils/getPlotImage.test.ts +14 -14
  123. package/src/utils/getPlotImage.ts +10 -10
  124. package/src/utils/getRandomUnlockedCrop.ts +5 -3
  125. package/src/utils/getRandomizedLifespan.test.ts +2 -8
  126. package/src/utils/getValueAdjustmentStream.test.ts +9 -0
  127. package/src/utils/getValueAdjustmentStream.ts +5 -0
  128. package/src/utils/isItemAFarmProduct.ts +2 -2
  129. package/src/utils/shouldPrecipitateToday.ts +3 -1
  130. package/src/utils/shouldStormToday.ts +2 -1
  131. package/src/utils/transformStateDataForImport.ts +3 -5
@@ -2,7 +2,6 @@ import Divider from '@mui/material/Divider/index.js'
2
2
  import Grid from '@mui/material/Grid/index.js'
3
3
  import Paper from '@mui/material/Paper/index.js'
4
4
  import { Theme } from '@mui/material/styles/index.js'
5
- import { array, bool, func, object, string } from 'prop-types'
6
5
 
7
6
  import { quickSelectSx } from '../../styles/sx.js'
8
7
  import FarmhandContext from '../Farmhand/Farmhand.context.js'
@@ -64,17 +63,6 @@ const ForestQuickSelect = ({
64
63
  </Paper>
65
64
  )
66
65
 
67
- ForestQuickSelect.propTypes = {
68
- mulchInventory: array.isRequired,
69
- handleForestItemSelectClick: func,
70
- handleItemSelectClick: func,
71
- isMenuOpen: bool,
72
- plantableTreeInventory: array.isRequired,
73
- playerInventoryQuantities: object.isRequired,
74
- selectedForestItemId: string.isRequired,
75
- selectedItemId: string.isRequired,
76
- }
77
-
78
66
  export default function Consumer(
79
67
  props: Partial<Parameters<typeof ForestQuickSelect>[0]>
80
68
  ) {
@@ -7,7 +7,6 @@ import Card from '@mui/material/Card/index.js'
7
7
  import CardContent from '@mui/material/CardContent/index.js'
8
8
  import Divider from '@mui/material/Divider/index.js'
9
9
  import globalWindow from 'global/window.js'
10
- import { func, object } from 'prop-types'
11
10
  import ReactMarkdown from 'react-markdown'
12
11
 
13
12
  import { items } from '../../img/index.js'
@@ -289,11 +288,6 @@ If you're playing on a mobile device, all you need to do is [add it to your home
289
288
  </Div>
290
289
  )
291
290
 
292
- Home.propTypes = {
293
- completedAchievements: object.isRequired,
294
- handleViewChangeButtonClick: func.isRequired,
295
- }
296
-
297
291
  export default function Consumer(props: Partial<Parameters<typeof Home>[0]>) {
298
292
  return (
299
293
  <FarmhandContext.Consumer>
@@ -10,7 +10,7 @@ const randomInt = (min: number, max: number) => {
10
10
 
11
11
  // Taken from:
12
12
  // https://github.com/alampros/react-confetti/blob/484bad0a0aaddbcfcc2fb4c1a4a7eeceaa6d4879/stories/snow.story.jsx#L7-L24
13
- const drawSnowflake = function(
13
+ const drawSnowflake = function (
14
14
  this: { numPoints?: number; radius: number },
15
15
  ctx: CanvasRenderingContext2D
16
16
  ) {
@@ -1,5 +1,4 @@
1
1
  import classNames from 'classnames'
2
- import { object, shape, string } from 'prop-types'
3
2
 
4
3
  import { itemsMap } from '../../data/maps.js'
5
4
  import { colors } from '../../styles/tokens.js'
@@ -46,9 +45,3 @@ export default function IngredientsList({
46
45
  </ul>
47
46
  )
48
47
  }
49
-
50
- IngredientsList.propTypes = {
51
- playerInventoryQuantities: object.isRequired,
52
- recipe: shape({ ingredients: object.isRequired, name: string.isRequired })
53
- .isRequired,
54
- }
@@ -45,7 +45,7 @@ const StubInventory = ({ gameState = {}, ...overrides }) => {
45
45
  describe('Inventory Component', () => {
46
46
  describe('Displaying items', () => {
47
47
  test('displays all items when no categories are selected', () => {
48
- const items = ([
48
+ const items = [
49
49
  testItem({ id: 'carrot', name: 'Carrot', type: 'CROP' as any }),
50
50
  testItem({ id: 'pumpkin', name: 'Pumpkin', type: 'CROP' as any }),
51
51
  testItem({
@@ -53,7 +53,7 @@ describe('Inventory Component', () => {
53
53
  name: 'Carrot Seed',
54
54
  type: 'SEEDS' as any,
55
55
  }),
56
- ] as unknown) as farmhand.item[]
56
+ ] as unknown as farmhand.item[]
57
57
 
58
58
  render(<StubInventory items={items} selectedCategories={[]} />)
59
59
  items.forEach(item => {
@@ -62,14 +62,14 @@ describe('Inventory Component', () => {
62
62
  })
63
63
 
64
64
  test('filters items by search query', () => {
65
- const items = ([
65
+ const items = [
66
66
  testItem({ id: 'carrot', name: 'Carrot', type: 'CROP' as any }),
67
67
  testItem({
68
68
  id: 'pumpkin-seed',
69
69
  name: 'Pumpkin Seed',
70
70
  type: 'SEEDS' as any,
71
71
  }),
72
- ] as unknown) as farmhand.item[]
72
+ ] as unknown as farmhand.item[]
73
73
 
74
74
  render(<StubInventory items={items} selectedCategories={[]} />)
75
75
 
@@ -5,7 +5,6 @@ import AccordionDetails from '@mui/material/AccordionDetails/index.js'
5
5
  import Checkbox from '@mui/material/Checkbox/index.js'
6
6
  import FormControlLabel from '@mui/material/FormControlLabel/index.js'
7
7
  import ExpandMoreIcon from '@mui/icons-material/ExpandMore.js'
8
- import { array } from 'prop-types'
9
8
 
10
9
  import FarmhandContext, { ContextData } from '../Farmhand/Farmhand.context.js'
11
10
  import Item from '../Item/index.js'
@@ -109,10 +108,9 @@ const Inventory = ({
109
108
  )
110
109
  }
111
110
 
112
- const filteredCategories = (Array.from(itemCategories.entries()) as [
113
- string,
114
- farmhand.item[]
115
- ][]).reduce(
111
+ const filteredCategories = (
112
+ Array.from(itemCategories.entries()) as [string, farmhand.item[]][]
113
+ ).reduce(
116
114
  (
117
115
  filtered: Map<string, farmhand.item[]>,
118
116
  [category, categoryItems]: [string, farmhand.item[]]
@@ -215,12 +213,6 @@ const Inventory = ({
215
213
  )
216
214
  }
217
215
 
218
- Inventory.propTypes = {
219
- items: array.isRequired,
220
- playerInventory: array,
221
- shopInventory: array,
222
- }
223
-
224
216
  export default function Consumer(
225
217
  props: Partial<Parameters<typeof Inventory>[0]>
226
218
  ) {
@@ -9,7 +9,6 @@ import CardContent from '@mui/material/CardContent/index.js'
9
9
  import CardActions from '@mui/material/CardActions/index.js'
10
10
  import Tooltip from '@mui/material/Tooltip/index.js'
11
11
  import Typography from '@mui/material/Typography/index.js'
12
- import { array, bool, func, number, object } from 'prop-types'
13
12
  import classNames from 'classnames'
14
13
 
15
14
  import FarmhandContext, { ContextData } from '../Farmhand/Farmhand.context.js'
@@ -455,26 +454,6 @@ export const Item = ({
455
454
  )
456
455
  }
457
456
 
458
- Item.propTypes = {
459
- adjustedValue: number,
460
- completedAchievements: object.isRequired,
461
- handleItemPurchaseClick: func,
462
- handleItemSelectClick: func,
463
- handleItemSellClick: func,
464
- historicalValueAdjustments: array.isRequired,
465
- inventory: array.isRequired,
466
- inventoryLimit: number.isRequired,
467
- isPurchaseView: bool,
468
- isSelectView: bool,
469
- isSelected: bool,
470
- isSellView: bool,
471
- item: object.isRequired,
472
- money: number.isRequired,
473
- playerInventoryQuantities: object.isRequired,
474
- showQuantity: bool,
475
- valueAdjustments: object.isRequired,
476
- }
477
-
478
457
  export default function Consumer(props: Partial<ItemProps>) {
479
458
  return (
480
459
  <FarmhandContext.Consumer>
@@ -2,7 +2,6 @@ import Button from '@mui/material/Button/index.js'
2
2
  import Tooltip from '@mui/material/Tooltip/index.js'
3
3
  import Typography from '@mui/material/Typography/index.js'
4
4
  import classNames from 'classnames'
5
- import { array, func, object, string } from 'prop-types'
6
5
 
7
6
  import { items as itemImages, pixel } from '../../img/index.js'
8
7
  import { spriteShadowSx, squareImgSx } from '../../styles/sx.js'
@@ -27,9 +26,10 @@ export const ItemList = ({
27
26
  sx={{
28
27
  display: 'flex',
29
28
  flexFlow: 'row',
30
- [`@media (orientation: landscape) and (min-height: ${breakpoints.largePhone}px)`]: {
31
- flexFlow: 'column',
32
- },
29
+ [`@media (orientation: landscape) and (min-height: ${breakpoints.largePhone}px)`]:
30
+ {
31
+ flexFlow: 'column',
32
+ },
33
33
  }}
34
34
  >
35
35
  {sortItems(items).map((item: farmhand.item) => (
@@ -98,10 +98,3 @@ export const ItemList = ({
98
98
  ))}
99
99
  </Div>
100
100
  )
101
-
102
- ItemList.propTypes = {
103
- handleItemSelectClick: func,
104
- items: array.isRequired,
105
- playerInventoryQuantities: object.isRequired,
106
- selectedItemId: string.isRequired,
107
- }
@@ -63,6 +63,4 @@ const KeybindingsView = () => (
63
63
  </div>
64
64
  )
65
65
 
66
- KeybindingsView.propTypes = {}
67
-
68
66
  export default KeybindingsView
@@ -1,5 +1,4 @@
1
1
  import React from 'react'
2
- import { array } from 'prop-types'
3
2
  import Alert from '@mui/material/Alert/index.js'
4
3
  import { AlertColor } from '@mui/material'
5
4
  import ReactMarkdown from 'react-markdown'
@@ -88,11 +87,6 @@ export const LogView = ({
88
87
  </Div>
89
88
  )
90
89
 
91
- LogView.propTypes = {
92
- notificationLog: array.isRequired,
93
- todaysNotifications: array.isRequired,
94
- }
95
-
96
90
  export default function Consumer(
97
91
  props: Partial<Parameters<typeof LogView>[0]>
98
92
  ) {
@@ -1,5 +1,4 @@
1
1
  import React from 'react'
2
- import { number, object } from 'prop-types'
3
2
 
4
3
  import Box from '@mui/material/Box/index.js'
5
4
  import CircularProgress from '@mui/material/CircularProgress/index.js'
@@ -62,12 +61,6 @@ export function DayAndProgressContainer({
62
61
  )
63
62
  }
64
63
 
65
- DayAndProgressContainer.propTypes = {
66
- dayCount: number.isRequired,
67
- experience: number.isRequired,
68
- itemsSold: object.isRequired,
69
- }
70
-
71
64
  export default function Consumer(
72
65
  props: Partial<Parameters<typeof DayAndProgressContainer>[0]>
73
66
  ) {
@@ -22,7 +22,6 @@ import Switch from '@mui/material/Switch/index.js'
22
22
  import TextField from '@mui/material/TextField/index.js'
23
23
  import Tooltip from '@mui/material/Tooltip/index.js'
24
24
  import Typography from '@mui/material/Typography/index.js'
25
- import { array, bool, func, number, string } from 'prop-types'
26
25
 
27
26
  import { MAX_ROOM_NAME_LENGTH } from '../../common/constants.js'
28
27
  import {
@@ -492,28 +491,6 @@ export const Navigation = ({
492
491
  )
493
492
  }
494
493
 
495
- Navigation.propTypes = {
496
- activePlayers: number,
497
- blockInput: bool.isRequired,
498
- farmName: string.isRequired,
499
- handleClickDialogViewButton: func.isRequired,
500
- handleChatRoomOpenStateChange: func.isRequired,
501
- handleActivePlayerButtonClick: func.isRequired,
502
- handleCloseDialogView: func.isRequired,
503
- handleDialogViewExited: func.isRequired,
504
- handleFarmNameUpdate: func.isRequired,
505
- handleOnlineToggleChange: func.isRequired,
506
- handleRoomChange: func.isRequired,
507
- handleViewChange: func.isRequired,
508
- inventory: array.isRequired,
509
- inventoryLimit: number.isRequired,
510
- isChatAvailable: bool.isRequired,
511
- isDialogViewOpen: bool.isRequired,
512
- isOnline: bool.isRequired,
513
- stageFocus: string.isRequired,
514
- viewList: array.isRequired,
515
- }
516
-
517
494
  export default function Consumer(
518
495
  props: Partial<Parameters<typeof Navigation>[0]>
519
496
  ) {
@@ -2,11 +2,14 @@ import React from 'react'
2
2
  import { render } from '@testing-library/react'
3
3
  import { SnackbarProvider } from 'notistack'
4
4
 
5
+ import { NOTIFICATION_DURATION_DEFAULT } from '../../constants.js'
6
+
5
7
  import { NotificationSystem, getNotificationKey } from './NotificationSystem.js'
6
8
 
7
9
  const defaultProps = {
8
10
  enqueueSnackbar: vitest.fn(),
9
11
  latestNotification: null,
12
+ notificationDuration: NOTIFICATION_DURATION_DEFAULT,
10
13
  }
11
14
 
12
15
  const renderWithSnackbar = (component: React.ReactElement) => {
@@ -44,7 +47,7 @@ test('calls enqueueSnackbar with a content-derived key when latestNotification i
44
47
 
45
48
  expect(enqueueSnackbar).toHaveBeenCalledWith(latestNotification, {
46
49
  key: 'info:Test notification',
47
- autoHideDuration: 1, // NOTIFICATION_DURATION in test mode
50
+ autoHideDuration: 1,
48
51
  preventDuplicate: true,
49
52
  })
50
53
  })
@@ -1,10 +1,9 @@
1
1
  import React, { useEffect } from 'react'
2
- import { func, shape, string } from 'prop-types'
3
2
  import Alert from '@mui/material/Alert/index.js'
4
3
  import ReactMarkdown from 'react-markdown'
5
4
  import { withSnackbar } from 'notistack'
6
5
 
7
- import { NOTIFICATION_DURATION } from '../../constants.js'
6
+ import { getNotificationDuration } from '../../constants.js'
8
7
  import FarmhandContext from '../Farmhand/Farmhand.context.js'
9
8
 
10
9
  export const getNotificationKey = ({
@@ -38,9 +37,11 @@ export const snackbarProviderContentCallback = (
38
37
  export const NotificationSystem = ({
39
38
  enqueueSnackbar,
40
39
  latestNotification,
40
+ notificationDuration,
41
41
  }: {
42
42
  enqueueSnackbar: (notification: farmhand.notification, options: any) => void
43
43
  latestNotification: farmhand.notification | null
44
+ notificationDuration: number
44
45
  }) => {
45
46
  useEffect(() => {
46
47
  if (!latestNotification) {
@@ -55,22 +56,14 @@ export const NotificationSystem = ({
55
56
  // once autoHideDuration and a key are set - no onClose needed here.
56
57
  enqueueSnackbar(latestNotification, {
57
58
  key: getNotificationKey(latestNotification),
58
- autoHideDuration: NOTIFICATION_DURATION,
59
+ autoHideDuration: getNotificationDuration(notificationDuration),
59
60
  preventDuplicate: true,
60
61
  })
61
- }, [enqueueSnackbar, latestNotification])
62
+ }, [enqueueSnackbar, latestNotification, notificationDuration])
62
63
 
63
64
  return null
64
65
  }
65
66
 
66
- NotificationSystem.propTypes = {
67
- latestNotification: shape({
68
- message: string.isRequired,
69
- onClick: func,
70
- severity: string.isRequired,
71
- }),
72
- }
73
-
74
67
  export default withSnackbar(function Consumer(props: any) {
75
68
  return (
76
69
  <FarmhandContext.Consumer>
@@ -71,7 +71,7 @@ test('does not render CowCard when no cow is offered for trade', () => {
71
71
  test('renders CowCard when cow is offered for trade', () => {
72
72
  const peerWithCow = {
73
73
  ...defaultPeer,
74
- cowOfferedForTrade: ({
74
+ cowOfferedForTrade: {
75
75
  id: 'test-cow',
76
76
  name: 'Test Cow',
77
77
  color: 'BROWN',
@@ -82,7 +82,7 @@ test('renders CowCard when cow is offered for trade', () => {
82
82
  gender: 'FEMALE',
83
83
  colorsInBloodline: { BROWN: true },
84
84
  originalOwnerId: 'peer-123',
85
- } as unknown) as farmhand.cow,
85
+ } as unknown as farmhand.cow,
86
86
  }
87
87
 
88
88
  render(<OnlinePeer peer={peerWithCow} />)
@@ -1,5 +1,4 @@
1
1
  import React from 'react'
2
- import { number, object, shape, string } from 'prop-types'
3
2
  import Card from '@mui/material/Card/index.js'
4
3
  import CardContent from '@mui/material/CardContent/index.js'
5
4
  import CardHeader from '@mui/material/CardHeader/index.js'
@@ -54,14 +53,4 @@ const OnlinePeer = ({
54
53
  )
55
54
  }
56
55
 
57
- OnlinePeer.propTypes = {
58
- peer: shape({
59
- cowOfferedForTrade: object,
60
- dayCount: number.isRequired,
61
- experience: number.isRequired,
62
- playerId: string.isRequired,
63
- money: number.isRequired,
64
- }).isRequired,
65
- }
66
-
67
56
  export default OnlinePeer
@@ -5,7 +5,6 @@ import Divider from '@mui/material/Divider/index.js'
5
5
  import Card from '@mui/material/Card/index.js'
6
6
  import CardContent from '@mui/material/CardContent/index.js'
7
7
  import sortBy from 'lodash.sortby'
8
- import { array, number, object, string } from 'prop-types'
9
8
 
10
9
  import BailOutErrorBoundary from '../BailOutErrorBoundary/index.js'
11
10
 
@@ -117,15 +116,6 @@ const OnlinePeersView = ({
117
116
  )
118
117
  }
119
118
 
120
- OnlinePeersView.propTypes = {
121
- activePlayers: number.isRequired,
122
- cowIdOfferedForTrade: string.isRequired,
123
- cowInventory: array.isRequired,
124
- playerId: string.isRequired,
125
- latestPeerMessages: array.isRequired,
126
- peers: object.isRequired,
127
- }
128
-
129
119
  export { OnlinePeersView }
130
120
 
131
121
  export default function Consumer(
@@ -165,9 +165,9 @@ export const Plot = ({
165
165
 
166
166
  const showPlotImage = Boolean(
167
167
  image &&
168
- (wasJustShoveled ||
169
- plotContent?.itemId ||
170
- (plotContent && getPlotContentType(plotContent) === itemType.CROP))
168
+ (wasJustShoveled ||
169
+ plotContent?.itemId ||
170
+ (plotContent && getPlotContentType(plotContent) === itemType.CROP))
171
171
  )
172
172
 
173
173
  let plotLabelText: string | null = null
@@ -1,5 +1,4 @@
1
1
  import React from 'react'
2
- import { object } from 'prop-types'
3
2
  import Divider from '@mui/material/Divider/index.js'
4
3
 
5
4
  import { itemsMap } from '../../data/maps.js'
@@ -44,11 +43,6 @@ const PriceEventView = ({
44
43
  </div>
45
44
  )
46
45
 
47
- PriceEventView.propTypes = {
48
- priceCrashes: object.isRequired,
49
- priceSurges: object.isRequired,
50
- }
51
-
52
46
  export { PriceEventView }
53
47
 
54
48
  export default function Consumer(
@@ -1,5 +1,4 @@
1
1
  import React, { useState, useEffect, useRef } from 'react'
2
- import { number } from 'prop-types'
3
2
  import { interpolate, tween } from 'shifty'
4
3
 
5
4
  import { Div, P } from '../Elements/index.js'
@@ -116,8 +115,4 @@ const ProgressBar = ({ percent }: { percent: number }) => {
116
115
  )
117
116
  }
118
117
 
119
- ProgressBar.propTypes = {
120
- percent: number.isRequired,
121
- }
122
-
123
118
  export default ProgressBar
@@ -1,5 +1,4 @@
1
1
  import React, { forwardRef } from 'react'
2
- import { func, number } from 'prop-types'
3
2
  import Fab from '@mui/material/Fab/index.js'
4
3
  import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp.js'
5
4
  import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown.js'
@@ -187,14 +186,6 @@ const QuantityInput = ({
187
186
  )
188
187
  }
189
188
 
190
- QuantityInput.propTypes = {
191
- handleSubmit: func.isRequired,
192
- handleUpdateNumber: func.isRequired,
193
- maxQuantity: number.isRequired,
194
- setQuantity: func.isRequired,
195
- value: number,
196
- }
197
-
198
189
  QuantityInput.defaultProps = {
199
190
  value: 1,
200
191
  }
@@ -2,7 +2,6 @@ import Divider from '@mui/material/Divider/index.js'
2
2
  import Grid from '@mui/material/Grid/index.js'
3
3
  import Paper from '@mui/material/Paper/index.js'
4
4
  import { Theme } from '@mui/material/styles/index.js'
5
- import { array, bool, func, object, string } from 'prop-types'
6
5
 
7
6
  import { quickSelectSx } from '../../styles/sx.js'
8
7
  import FarmhandContext from '../Farmhand/Farmhand.context.js'
@@ -61,15 +60,6 @@ const QuickSelect = ({
61
60
  </Paper>
62
61
  )
63
62
 
64
- QuickSelect.propTypes = {
65
- fieldToolInventory: array.isRequired,
66
- handleItemSelectClick: func,
67
- isMenuOpen: bool,
68
- plantableCropInventory: array.isRequired,
69
- playerInventoryQuantities: object.isRequired,
70
- selectedItemId: string.isRequired,
71
- }
72
-
73
63
  export default function Consumer(
74
64
  props: Partial<Parameters<typeof QuickSelect>[0]>
75
65
  ) {
@@ -6,7 +6,6 @@ import CardHeader from '@mui/material/CardHeader/index.js'
6
6
  import CardContent from '@mui/material/CardContent/index.js'
7
7
  import CardActions from '@mui/material/CardActions/index.js'
8
8
  import Typography from '@mui/material/Typography/index.js'
9
- import { array, func, number, object } from 'prop-types'
10
9
 
11
10
  import { totalIngredientsInRecipe } from '../../utils/totalIngredientsInRecipe.js'
12
11
  import { canMakeRecipe } from '../../utils/canMakeRecipe.js'
@@ -141,14 +140,6 @@ const Recipe = ({
141
140
  )
142
141
  }
143
142
 
144
- Recipe.propTypes = {
145
- handleMakeRecipeClick: func.isRequired,
146
- inventory: array.isRequired,
147
- inventoryLimit: number.isRequired,
148
- playerInventoryQuantities: object.isRequired,
149
- recipe: object.isRequired,
150
- }
151
-
152
143
  export { Recipe }
153
144
 
154
145
  export default function Consumer(props: Partial<Parameters<typeof Recipe>[0]>) {
@@ -1,5 +1,4 @@
1
1
  import React, { useState } from 'react'
2
- import PropTypes from 'prop-types'
3
2
 
4
3
  import SearchBar from '../SearchBar/index.js'
5
4
  import Recipe from '../Recipe/index.js'
@@ -48,8 +47,3 @@ export function RecipeList({
48
47
  </>
49
48
  )
50
49
  }
51
-
52
- RecipeList.propTypes = {
53
- allRecipes: PropTypes.object.isRequired,
54
- learnedRecipes: PropTypes.array.isRequired,
55
- }
@@ -1,5 +1,4 @@
1
1
  import React from 'react'
2
- import PropTypes from 'prop-types'
3
2
  import { useDebounceCallback } from 'usehooks-ts'
4
3
  import TextField from '@mui/material/TextField/index.js'
5
4
 
@@ -81,9 +80,4 @@ const SearchBar = ({
81
80
  )
82
81
  }
83
82
 
84
- SearchBar.propTypes = {
85
- placeholder: PropTypes.string,
86
- onSearch: PropTypes.func.isRequired,
87
- }
88
-
89
83
  export default SearchBar
@@ -6,13 +6,11 @@ import FarmhandContext, {
6
6
  createContextData,
7
7
  } from '../Farmhand/Farmhand.context.js'
8
8
 
9
- import { RandomSeedInput } from './RandomSeedInput.js'
9
+ import { RandomSeedInput, RandomSeedInputProps } from './RandomSeedInput.js'
10
10
 
11
11
  const mockHandleRNGSeedChange = vitest.fn()
12
12
 
13
- const MockRandomSeedInput = (
14
- props: React.PropsWithChildren<Record<string, unknown>>
15
- ) => {
13
+ const MockRandomSeedInput = (props: RandomSeedInputProps) => {
16
14
  const contextValue = createContextData()
17
15
 
18
16
  contextValue.handlers.handleRNGSeedChange = mockHandleRNGSeedChange
@@ -1,16 +1,17 @@
1
1
  import React, { useContext, useState } from 'react'
2
- import { string } from 'prop-types'
3
2
  import globalWindow from 'global/window.js'
4
3
  import TextField from '@mui/material/TextField/index.js'
5
4
 
6
5
  import FarmhandContext from '../Farmhand/Farmhand.context.js'
7
6
  import { Form } from '../Elements/index.js'
8
7
 
8
+ export interface RandomSeedInputProps {
9
+ search?: string
10
+ }
11
+
9
12
  export const RandomSeedInput = ({
10
13
  search = globalWindow.location.search,
11
- }: {
12
- search?: string
13
- }) => {
14
+ }: RandomSeedInputProps) => {
14
15
  const {
15
16
  handlers: { handleRNGSeedChange },
16
17
  } = useContext(FarmhandContext)
@@ -47,7 +48,3 @@ export const RandomSeedInput = ({
47
48
  </Form>
48
49
  )
49
50
  }
50
-
51
- RandomSeedInput.propTypes = {
52
- search: string,
53
- }
@@ -17,10 +17,12 @@ const defaultProps = {
17
17
  handleExportDataClick: noop,
18
18
  handleImportDataClick: noop,
19
19
  handleSaveButtonClick: noop,
20
+ handleNotificationDurationChange: noop,
20
21
  handleShowNotificationsChange: noop,
21
22
  handleUseAlternateEndDayButtonPositionChange: noop,
22
23
  handleShowHomeScreenChange: noop,
23
24
  showNotifications: true,
25
+ notificationDuration: 6000,
24
26
  useAlternateEndDayButtonPosition: false,
25
27
  showHomeScreen: false,
26
28
  }
@@ -144,6 +146,25 @@ test('handles switch toggling', async () => {
144
146
  expect(handleAllowCustomPeerCowNamesChange).toHaveBeenCalledTimes(1)
145
147
  })
146
148
 
149
+ test('handles notification duration changes', async () => {
150
+ const user = userEvent.setup()
151
+ const handleNotificationDurationChange = vitest.fn()
152
+
153
+ render(
154
+ <SettingsView
155
+ {...defaultProps}
156
+ handleNotificationDurationChange={handleNotificationDurationChange}
157
+ />
158
+ )
159
+
160
+ const slider = screen.getByRole('slider')
161
+
162
+ await user.click(slider)
163
+ await user.keyboard('{ArrowRight}')
164
+
165
+ expect(handleNotificationDurationChange).toHaveBeenCalled()
166
+ })
167
+
147
168
  test('opens delete confirmation dialog when delete button is clicked', async () => {
148
169
  const user = userEvent.setup()
149
170