diff --git a/package-lock.json b/package-lock.json
index 6f810530e..aef0e2ff2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@jeremyckahn/farmhand",
- "version": "1.18.4",
+ "version": "1.18.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@jeremyckahn/farmhand",
- "version": "1.18.4",
+ "version": "1.18.5",
"license": "GPL-2.0-or-later",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.27",
@@ -45,6 +45,7 @@
"react-confetti": "^6.1.0",
"react-dom": "^17.0.2",
"react-file-reader-input": "^2.0.0",
+ "react-helmet": "^6.1.0",
"react-hotkeys": "^2.0.0",
"react-markdown": "^4.3.1",
"react-number-format": "^4.4.1",
@@ -26995,6 +26996,11 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/react-fast-compare": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
+ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
+ },
"node_modules/react-file-reader-input": {
"version": "2.0.0",
"license": "MIT",
@@ -27003,6 +27009,20 @@
"react-dom": "^15.0.0 || ^16.0.0"
}
},
+ "node_modules/react-helmet": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz",
+ "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==",
+ "dependencies": {
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.7.2",
+ "react-fast-compare": "^3.1.1",
+ "react-side-effect": "^2.1.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.3.0"
+ }
+ },
"node_modules/react-hotkeys": {
"version": "2.0.0",
"license": "ISC",
@@ -27537,6 +27557,14 @@
"node": ">= 10.0.0"
}
},
+ "node_modules/react-side-effect": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz",
+ "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==",
+ "peerDependencies": {
+ "react": "^16.3.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/react-test-renderer": {
"version": "16.14.0",
"dev": true,
@@ -51959,9 +51987,25 @@
"version": "6.0.11",
"dev": true
},
+ "react-fast-compare": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz",
+ "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
+ },
"react-file-reader-input": {
"version": "2.0.0"
},
+ "react-helmet": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz",
+ "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==",
+ "requires": {
+ "object-assign": "^4.1.1",
+ "prop-types": "^15.7.2",
+ "react-fast-compare": "^3.1.1",
+ "react-side-effect": "^2.1.0"
+ }
+ },
"react-hotkeys": {
"version": "2.0.0",
"requires": {
@@ -52305,6 +52349,11 @@
}
}
},
+ "react-side-effect": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz",
+ "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw=="
+ },
"react-test-renderer": {
"version": "16.14.0",
"dev": true,
diff --git a/package.json b/package.json
index ddc6cfb9e..f9312a3f1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@jeremyckahn/farmhand",
- "version": "1.18.4",
+ "version": "1.18.5",
"publishConfig": {
"access": "public"
},
@@ -121,6 +121,7 @@
"react-confetti": "^6.1.0",
"react-dom": "^17.0.2",
"react-file-reader-input": "^2.0.0",
+ "react-helmet": "^6.1.0",
"react-hotkeys": "^2.0.0",
"react-markdown": "^4.3.1",
"react-number-format": "^4.4.1",
diff --git a/src/components/ChatRoom/ChatRoom.js b/src/components/ChatRoom/ChatRoom.js
new file mode 100644
index 000000000..c948ddcf2
--- /dev/null
+++ b/src/components/ChatRoom/ChatRoom.js
@@ -0,0 +1,76 @@
+import React, { useContext } from 'react'
+import { Helmet } from 'react-helmet'
+import classNames from 'classnames'
+import Button from '@material-ui/core/Button'
+import Dialog from '@material-ui/core/Dialog'
+import DialogTitle from '@material-ui/core/DialogTitle'
+import DialogContent from '@material-ui/core/DialogContent'
+import DialogActions from '@material-ui/core/DialogActions'
+import Typography from '@material-ui/core/Typography'
+
+import FarmhandContext from '../Farmhand/Farmhand.context'
+
+import './ChatRoom.sass'
+
+const chitchatterDomain = 'https://chitchatter.im'
+
+export const ChatRoom = () => {
+ const dialogTitleId = 'chat-title'
+ const dialogContentId = 'chat-content'
+
+ const {
+ handlers: { handleChatRoomOpenStateChange },
+ gameState: { id, isChatOpen, room },
+ } = useContext(FarmhandContext)
+
+ const handleChatRoomClose = () => {
+ handleChatRoomOpenStateChange(false)
+ }
+
+ const chatRoomComponent = (
+ // @ts-ignore
+
+ )
+
+ return (
+ <>
+
+
+
+
+ >
+ )
+}
diff --git a/src/components/ChatRoom/ChatRoom.sass b/src/components/ChatRoom/ChatRoom.sass
new file mode 100644
index 000000000..afcdfee4f
--- /dev/null
+++ b/src/components/ChatRoom/ChatRoom.sass
@@ -0,0 +1,4 @@
+.ChatRoom
+ .MuiDialog-container
+ padding: 1em
+ height: calc(100% - 2em)
diff --git a/src/components/ChatRoom/index.js b/src/components/ChatRoom/index.js
new file mode 100644
index 000000000..ed1ce9d5d
--- /dev/null
+++ b/src/components/ChatRoom/index.js
@@ -0,0 +1 @@
+export * from './ChatRoom'
diff --git a/src/components/Farmhand/Farmhand.js b/src/components/Farmhand/Farmhand.js
index 267e99a37..de49cc547 100644
--- a/src/components/Farmhand/Farmhand.js
+++ b/src/components/Farmhand/Farmhand.js
@@ -118,6 +118,8 @@ import { endpoints, rtcConfig, trackerUrls } from '../../config'
import { scarecrow } from '../../data/items'
+import { ChatRoom } from '../ChatRoom'
+
import { getInventoryQuantities } from './helpers/getInventoryQuantities'
import FarmhandContext from './Farmhand.context'
import { FarmhandReducers } from './FarmhandReducers'
@@ -238,6 +240,7 @@ const applyPriceEvents = (valueAdjustments, priceCrashes, priceSurges) => {
* of that cellar item sold. The numbers in this map represent a subset of the
* corresponding ones in itemsSold. cellarItemsSold is intended to be used for
* internal bookkeeping.
+ * @property {boolean} isChatOpen Whether the chat modal is open.
* @property {boolean} isDialogViewOpen
* @property {boolean} isOnline Whether the player is playing online.
* @property {boolean} isWaitingForDayToCompleteIncrementing
@@ -399,6 +402,11 @@ export default class Farmhand extends FarmhandReducers {
)
}
+ get isChatAvailable() {
+ const { isOnline, room } = this.state
+ return isOnline && room !== DEFAULT_ROOM
+ }
+
/**
* @returns {farmhand.state}
*/
@@ -446,6 +454,7 @@ export default class Farmhand extends FarmhandReducers {
isMenuOpen: !doesMenuObstructStage(),
itemsSold: {},
cellarItemsSold: {},
+ isChatOpen: false,
isDialogViewOpen: false,
isOnline: this.props.match.path.startsWith('/online'),
isWaitingForDayToCompleteIncrementing: false,
@@ -1268,6 +1277,7 @@ export default class Farmhand extends FarmhandReducers {
state: { redirect },
fieldToolInventory,
handlers,
+ isChatAvailable,
keyHandlers,
keyMap,
levelEntitlements,
@@ -1287,6 +1297,7 @@ export default class Farmhand extends FarmhandReducers {
blockInput,
features,
fieldToolInventory,
+ isChatAvailable,
levelEntitlements,
plantableCropInventory,
playerInventory,
@@ -1424,6 +1435,7 @@ export default class Farmhand extends FarmhandReducers {
+ {isChatAvailable ? : null}
diff --git a/src/components/Navigation/Navigation.js b/src/components/Navigation/Navigation.js
index f5c06cb8e..5ca417409 100644
--- a/src/components/Navigation/Navigation.js
+++ b/src/components/Navigation/Navigation.js
@@ -31,7 +31,11 @@ import {
inventorySpaceConsumed,
} from '../../utils'
import { dialogView } from '../../enums'
-import { INFINITE_STORAGE_LIMIT, STAGE_TITLE_MAP } from '../../constants'
+import {
+ DEFAULT_ROOM,
+ INFINITE_STORAGE_LIMIT,
+ STAGE_TITLE_MAP,
+} from '../../constants'
import { MAX_ROOM_NAME_LENGTH } from '../../common/constants'
import AccountingView from '../AccountingView'
@@ -79,8 +83,10 @@ const FarmNameDisplay = ({ farmName, handleFarmNameUpdate }) => {
const OnlineControls = ({
activePlayers,
handleActivePlayerButtonClick,
+ handleChatRoomOpenStateChange,
handleOnlineToggleChange,
handleRoomChange,
+ isChatAvailable,
isOnline,
room,
}) => {
@@ -90,6 +96,10 @@ const OnlineControls = ({
setDisplayedRoom(room)
}, [room, setDisplayedRoom])
+ const handleChatButtonClick = () => {
+ handleChatRoomOpenStateChange(true)
+ }
+
return (
<>
{activePlayers && (
-
+ <>
+
+ {isChatAvailable ? (
+
+ ) : (
+
+ Chat is available for online rooms other than "{DEFAULT_ROOM}"
+
+ )}
+ >
)}
>
)
@@ -203,6 +228,7 @@ export const Navigation = ({
currentDialogView,
farmName,
handleActivePlayerButtonClick,
+ handleChatRoomOpenStateChange,
handleClickDialogViewButton,
handleCloseDialogView,
handleDialogViewExited,
@@ -212,6 +238,7 @@ export const Navigation = ({
handleViewChange,
inventory,
inventoryLimit,
+ isChatAvailable,
isDialogViewOpen,
isOnline,
room,
@@ -231,8 +258,10 @@ export const Navigation = ({
{...{
activePlayers,
handleActivePlayerButtonClick,
+ handleChatRoomOpenStateChange,
handleOnlineToggleChange,
handleRoomChange,
+ isChatAvailable,
isOnline,
room,
}}
@@ -335,6 +364,7 @@ Navigation.propTypes = {
blockInput: bool.isRequired,
farmName: string.isRequired,
handleClickDialogViewButton: func.isRequired,
+ handleChatRoomOpenStateChange: func.isRequired,
handleActivePlayerButtonClick: func.isRequired,
handleCloseDialogView: func.isRequired,
handleDialogViewExited: func.isRequired,
@@ -344,6 +374,7 @@ Navigation.propTypes = {
handleViewChange: func.isRequired,
inventory: array.isRequired,
inventoryLimit: number.isRequired,
+ isChatAvailable: bool.isRequired,
isDialogViewOpen: bool.isRequired,
isOnline: bool.isRequired,
stageFocus: string.isRequired,
diff --git a/src/components/Navigation/Navigation.sass b/src/components/Navigation/Navigation.sass
index fe8e036d7..ae3490e3b 100644
--- a/src/components/Navigation/Navigation.sass
+++ b/src/components/Navigation/Navigation.sass
@@ -87,3 +87,8 @@
.MuiSelect-select.MuiSelect-select
padding: 1em
+
+ .chat-placeholder
+ font-size: .75em
+ padding: .5em 0
+ text-align: center
diff --git a/src/components/Navigation/Navigation.test.js b/src/components/Navigation/Navigation.test.js
index c25be48ff..dd50ca981 100644
--- a/src/components/Navigation/Navigation.test.js
+++ b/src/components/Navigation/Navigation.test.js
@@ -20,6 +20,7 @@ beforeEach(() => {
dayCount: 0,
farmName: '',
handleActivePlayerButtonClick: noop,
+ handleChatRoomOpenStateChange: noop,
handleClickDialogViewButton: noop,
handleCloseDialogView: noop,
handleDialogViewExited: noop,
@@ -30,6 +31,7 @@ beforeEach(() => {
inventory: [],
inventoryLimit: INFINITE_STORAGE_LIMIT,
itemsSold: {},
+ isChatAvailable: false,
isDialogViewOpen: false,
isOnline: false,
stageFocus: stageFocusType.FIELD,
diff --git a/src/handlers/ui-events.js b/src/handlers/ui-events.js
index 279692718..41812f659 100644
--- a/src/handlers/ui-events.js
+++ b/src/handlers/ui-events.js
@@ -531,4 +531,11 @@ export default {
const newUrl = `${origin}${pathname}${newSearch}${hash}`
window.history.replaceState({}, '', newUrl)
},
+
+ /**
+ * @param {boolean} isChatOpen
+ */
+ handleChatRoomOpenStateChange(isChatOpen) {
+ this.setState({ isChatOpen })
+ },
}