diff --git a/package.json b/package.json
index d7a4a2f8..671f8089 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"next-transpile-modules": "^8.0.0",
"prop-types": "^15.7.2",
"react": "^17.0.2",
+ "react-color": "^2.19.3",
"react-dom": "^17.0.2",
"react-firebaseui": "^5.0.2",
"react-relay": "^12.0.0",
diff --git a/src/components/BackgroundColorPicker.js b/src/components/BackgroundColorPicker.js
new file mode 100644
index 00000000..884da4f9
--- /dev/null
+++ b/src/components/BackgroundColorPicker.js
@@ -0,0 +1,71 @@
+import React, { useCallback, useState } from 'react'
+import { makeStyles } from '@material-ui/core/styles'
+import { SketchPicker } from 'react-color'
+import { Typography } from '@material-ui/core'
+import PropTypes from 'prop-types'
+
+const useStyles = makeStyles((theme) => ({
+ root: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ },
+ gridList: {
+ display: 'flex',
+ flexDirection: 'row',
+ width: '100%',
+ },
+ previewContainer: {
+ marginTop: 0,
+ margin: theme.spacing(2),
+ width: '100%',
+ height: '60%',
+ },
+ header: {
+ paddingLeft: 0,
+ },
+ divider: {
+ marginBottom: 10,
+ },
+}))
+const BackgroundColorPicker = ({ user, onBackgroundColorSelection }) => {
+ const classes = useStyles()
+ const [selectedColor, setSelectedColor] = useState(
+ user.backgroundColor || '#000'
+ )
+
+ const onColorChanged = useCallback(
+ (color) => {
+ setSelectedColor(color.hex)
+ onBackgroundColorSelection(color.hex)
+ },
+ [onBackgroundColorSelection]
+ )
+
+ return (
+
+ )
+}
+
+BackgroundColorPicker.propTypes = {
+ user: PropTypes.shape({
+ backgroundColor: PropTypes.string.isRequired,
+ }).isRequired,
+ onBackgroundColorSelection: PropTypes.func.isRequired,
+}
+
+export default BackgroundColorPicker
diff --git a/src/components/BackgroundColorPicker.stories.jsx b/src/components/BackgroundColorPicker.stories.jsx
new file mode 100644
index 00000000..ea98bcef
--- /dev/null
+++ b/src/components/BackgroundColorPicker.stories.jsx
@@ -0,0 +1,37 @@
+import React from 'react'
+import { makeStyles } from '@material-ui/core/styles'
+import blue from '@material-ui/core/colors/blue'
+import BackgroundColorPicker from './BackgroundColorPicker'
+
+export default {
+ title: 'Components/BackgroundColorPicker',
+ component: BackgroundColorPicker,
+}
+
+const useStyles = makeStyles(() => ({
+ templateContainer: {
+ background: blue['200'],
+ height: 700,
+ },
+}))
+
+// eslint-disable-next-line react/jsx-props-no-spreading
+const Template = (args) => {
+ const classes = useStyles()
+ return (
+
+
+
+ )
+}
+
+export const normal = Template.bind({})
+normal.args = {
+ user: {
+ backgroundColor: '#138',
+ },
+ onBackgroundColorSelection: () => {
+ // eslint-disable-next-line no-console
+ console.log('onBackgroundColorSelection')
+ },
+}
diff --git a/src/components/__tests__/BackgroundColorPicker.test.js b/src/components/__tests__/BackgroundColorPicker.test.js
new file mode 100644
index 00000000..26435999
--- /dev/null
+++ b/src/components/__tests__/BackgroundColorPicker.test.js
@@ -0,0 +1,40 @@
+import React from 'react'
+import { shallow } from 'enzyme'
+import { SketchPicker } from 'react-color'
+
+jest.mock('react-color')
+
+const mockOnBackgroundColorSelection = jest.fn()
+const mockProps = {
+ user: {
+ backgroundColor: '#FF0000',
+ },
+ onBackgroundColorSelection: mockOnBackgroundColorSelection,
+}
+
+afterEach(() => {
+ jest.clearAllMocks()
+})
+
+describe('Background color picker component', () => {
+ it('renders without error', () => {
+ const BackgroundColorPicker =
+ require('src/components/BackgroundColorPicker').default
+ expect(() =>
+ shallow()
+ ).not.toThrow()
+ })
+
+ it('calls onBackgroundColorSelection callback when the color changes', () => {
+ const BackgroundColorPicker =
+ require('src/components/BackgroundColorPicker').default
+ const wrapper = shallow()
+
+ // Mock that our color picker fires its change callback
+ const colorData = {
+ hex: '#CDCDCD',
+ }
+ wrapper.find(SketchPicker).prop('onChangeComplete')(colorData)
+ expect(mockOnBackgroundColorSelection).toHaveBeenCalledWith('#CDCDCD')
+ })
+})
diff --git a/src/components/groupImpactComponents/GroupGoalNotification.js b/src/components/groupImpactComponents/GroupGoalNotification.js
index bc39b9e0..e4626731 100644
--- a/src/components/groupImpactComponents/GroupGoalNotification.js
+++ b/src/components/groupImpactComponents/GroupGoalNotification.js
@@ -7,6 +7,7 @@ import { ArrowForwardIos } from '@material-ui/icons'
import { GROUP_IMPACT_SIDEBAR_STATE } from 'src/utils/constants'
import gtag from 'ga-gtag'
import Handlebars from 'handlebars'
+import moment from 'moment'
import Notification from '../Notification'
const useStyles = makeStyles((theme) => ({
@@ -64,6 +65,7 @@ const GroupGoalNotification = ({
onGoalStarted,
impactTitle,
impactCountPerMetric,
+ dateStarted,
}) => {
const impactTitleTemplate = Handlebars.compile(impactTitle)
const impactTitleCompiled = impactTitleTemplate({
@@ -93,6 +95,10 @@ const GroupGoalNotification = ({
onGoalStarted()
}, [mode, onGoalStarted])
+ const dateStartedMoment = dateStarted && moment(dateStarted).format('l')
+ const startingString = `${
+ mode === GROUP_IMPACT_SIDEBAR_STATE.COMPLETED ? 'COMPLETED' : 'GOAL STARTED'
+ }${dateStarted ? ` - Week of ${dateStartedMoment}` : ''}`
return (
- {mode === GROUP_IMPACT_SIDEBAR_STATE.COMPLETED
- ? 'COMPLETED'
- : 'GOAL STARTED'}
- : {impactTitleCompiled}
+ {startingString}: {impactTitleCompiled}
}
buttons={
@@ -151,6 +154,11 @@ GroupGoalNotification.propTypes = {
onGoalStarted: PropTypes.func.isRequired,
impactTitle: PropTypes.string.isRequired,
impactCountPerMetric: PropTypes.number.isRequired,
+ dateStarted: PropTypes.string,
+}
+
+GroupGoalNotification.defaultProps = {
+ dateStarted: null,
}
export default GroupGoalNotification
diff --git a/src/components/groupImpactComponents/GroupGoalNotification.stories.jsx b/src/components/groupImpactComponents/GroupGoalNotification.stories.jsx
index 95d3c5dc..f099df95 100644
--- a/src/components/groupImpactComponents/GroupGoalNotification.stories.jsx
+++ b/src/components/groupImpactComponents/GroupGoalNotification.stories.jsx
@@ -22,4 +22,5 @@ started.args = {
mode: GROUP_IMPACT_SIDEBAR_STATE.NEW,
impactTitle: 'Fund {{count}} visits from a community healthworker',
impactCountPerMetric: 3,
+ dateStarted: '2020-01-10T10:00:00.000Z',
}
diff --git a/src/components/groupImpactComponents/GroupImpact.js b/src/components/groupImpactComponents/GroupImpact.js
index de291171..3dd31c4a 100644
--- a/src/components/groupImpactComponents/GroupImpact.js
+++ b/src/components/groupImpactComponents/GroupImpact.js
@@ -58,8 +58,14 @@ const GroupImpact = ({ user }) => {
GROUP_IMPACT_SIDEBAR_STATE.NORMAL
)
const [sidebarOpen, setSidebarOpen] = useState(false)
- const { id, dollarGoal, dollarProgressFromSearch, impactMetric } =
- groupImpactMetric
+ const {
+ id,
+ dollarGoal,
+ dollarProgressFromSearch,
+ impactMetric,
+ dateStarted,
+ dateExpires,
+ } = groupImpactMetric
const { impactTitle, impactCountPerMetric, whyValuableDescription } =
impactMetric
@@ -192,6 +198,7 @@ const GroupImpact = ({ user }) => {
onNextGoal={beginNewGoal}
onGoalStarted={onGoalStarted}
impactCountPerMetric={impactCountPerMetric}
+ dateStarted={dateExpires ? dateStarted : null}
/>
@@ -215,6 +222,8 @@ GroupImpact.propTypes = {
whyValuableDescription: PropTypes.string.isRequired,
impactCountPerMetric: PropTypes.number.isRequired,
}),
+ dateStarted: PropTypes.string,
+ dateExpires: PropTypes.string,
}).isRequired,
groupImpactMetricCount: PropTypes.number,
}).isRequired,
@@ -260,6 +269,8 @@ GroupImpactWrapper.propTypes = {
whyValuableDescription: PropTypes.string.isRequired,
impactCountPerMetric: PropTypes.number,
}),
+ dateStarted: PropTypes.string,
+ dateExpires: PropTypes.string,
}),
groupImpactMetricCount: PropTypes.number,
}).isRequired,
diff --git a/src/components/groupImpactComponents/GroupImpact.stories.jsx b/src/components/groupImpactComponents/GroupImpact.stories.jsx
index 0109df75..aee9c967 100644
--- a/src/components/groupImpactComponents/GroupImpact.stories.jsx
+++ b/src/components/groupImpactComponents/GroupImpact.stories.jsx
@@ -154,6 +154,8 @@ standardView.args = {
'Community health workers provide quality health care to those who might not otherwise have access.',
impactCountPerMetric: 3,
},
+ dateStarted: '2020-01-10T10:00:00.000Z',
+ dateExpires: '2020-07-10T10:00:00.000Z',
},
},
},
diff --git a/src/components/groupImpactComponents/GroupImpactContainer.js b/src/components/groupImpactComponents/GroupImpactContainer.js
index a3df758b..b327c15c 100644
--- a/src/components/groupImpactComponents/GroupImpactContainer.js
+++ b/src/components/groupImpactComponents/GroupImpactContainer.js
@@ -16,6 +16,8 @@ export default createFragmentContainer(GroupImpact, {
whyValuableDescription
impactCountPerMetric
}
+ dateStarted
+ dateExpires
}
groupImpactMetricCount
}
diff --git a/src/components/groupImpactComponents/GroupImpactSidebar.js b/src/components/groupImpactComponents/GroupImpactSidebar.js
index 10473400..6db8ac0a 100644
--- a/src/components/groupImpactComponents/GroupImpactSidebar.js
+++ b/src/components/groupImpactComponents/GroupImpactSidebar.js
@@ -30,6 +30,7 @@ import SearchIcon from '@material-ui/icons/Search'
import TabIcon from '@material-ui/icons/Tab'
import ToggleButton from '@material-ui/lab/ToggleButton'
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup'
+import moment from 'moment'
import VerticalLinearProgress from '../VerticalLinearProgress'
import GroupImpactLeaderboard from './GroupImpactLeaderboard'
import GroupImpactContributionWidget from './GroupImpactContributionWidget'
@@ -253,8 +254,16 @@ const GroupImpactSidebar = ({
setSelectedMode(newValue)
event.stopPropagation()
}
- const { dollarProgress, dollarGoal, dollarProgressFromSearch, impactMetric } =
- displayingOldGoal ? lastGroupImpactMetric : groupImpactMetric
+
+ const {
+ dollarProgress,
+ dollarGoal,
+ dollarProgressFromSearch,
+ impactMetric,
+ dateStarted,
+ dateExpires,
+ } = displayingOldGoal ? lastGroupImpactMetric : groupImpactMetric
+
const { impactTitle, whyValuableDescription, impactCountPerMetric } =
impactMetric
const classes = useStyles()
@@ -406,7 +415,7 @@ const GroupImpactSidebar = ({
- GROUP GOAL
+ {`${dateExpires ? 'WEEKLY ' : ''}GROUP GOAL`}
{groupImpactSidebarState ? (
@@ -422,6 +431,16 @@ const GroupImpactSidebar = ({
)}
+ {dateExpires &&
(
+
+ `${days > 0 ? `${days }days`}``
+
+ )}
+ />}
{impactTitleCompiled}
{absoluteProgress}%
diff --git a/yarn.lock b/yarn.lock
index e563b474..400fc5a0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2192,6 +2192,11 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
+"@icons/material@^0.2.4":
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
+ integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==
+
"@istanbuljs/load-nyc-config@^1.0.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
@@ -11296,6 +11301,11 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
+lodash-es@^4.17.15:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+ integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
lodash._reinterpolate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
@@ -11401,7 +11411,7 @@ lodash.uniq@4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
-lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
+lodash@^4.0.1, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -11572,6 +11582,11 @@ markdown-escapes@^1.0.0:
resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
+material-colors@^1.2.1:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
+ integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
+
material-design-lite@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/material-design-lite/-/material-design-lite-1.3.0.tgz#d004ce3fee99a1eeb74a78b8a325134a5f1171d3"
@@ -13364,7 +13379,7 @@ prop-types@15.7.2, prop-types@^15.7.0, prop-types@^15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"
-prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.8.1:
+prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -13615,6 +13630,19 @@ rc@^1.2.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
+react-color@^2.19.3:
+ version "2.19.3"
+ resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d"
+ integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==
+ dependencies:
+ "@icons/material" "^0.2.4"
+ lodash "^4.17.15"
+ lodash-es "^4.17.15"
+ material-colors "^1.2.1"
+ prop-types "^15.5.10"
+ reactcss "^1.2.0"
+ tinycolor2 "^1.4.1"
+
react-docgen-typescript@^2.1.1:
version "2.2.2"
resolved "https://registry.yarnpkg.com/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz#4611055e569edc071204aadb20e1c93e1ab1659c"
@@ -13767,6 +13795,13 @@ react@^17.0.2:
loose-envify "^1.1.0"
object-assign "^4.1.1"
+reactcss@^1.2.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
+ integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==
+ dependencies:
+ lodash "^4.0.1"
+
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
@@ -15280,10 +15315,10 @@ synchronous-promise@^2.0.15:
resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.16.tgz#669b75e86b4295fdcc1bb0498de9ac1af6fd51a9"
integrity sha512-qImOD23aDfnIDNqlG1NOehdB9IYsn1V9oByPjKY1nakv2MQYCEMyX033/q+aEtYCpmYK1cv2+NTmlH+ra6GA5A==
-tab-ads@^1.1.19:
- version "1.1.19"
- resolved "https://registry.yarnpkg.com/tab-ads/-/tab-ads-1.1.19.tgz#73d189c5e669b22679abdb7fc903a9be30994115"
- integrity sha512-8GDDkM83SFJ0HgfdBq7oFwYkJVNFeslWRTdhQ7e3PiHwvgH49X2dm/rlmgBlU28j1hozSy526/5Jxyx3ZUMqgw==
+tab-ads@^1.1.20:
+ version "1.1.20"
+ resolved "https://registry.yarnpkg.com/tab-ads/-/tab-ads-1.1.20.tgz#b3ef70a03127f746171daf81fa7d6461c9767977"
+ integrity sha512-dagHnOnf4827hQRmDZ+thvldFac5CuY7pEVSsVO/iJ+02xYc7/g2wn3d4wyQUifXjwf8AJBVCpEerckZAKANgA==
dependencies:
lodash "^4.17.21"
@@ -15501,6 +15536,11 @@ tiny-warning@^1.0.2:
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+tinycolor2@^1.4.1:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e"
+ integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==
+
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"