diff --git a/.bitmap b/.bitmap
index 8c0ea6a..7a57ba5 100644
--- a/.bitmap
+++ b/.bitmap
@@ -49,7 +49,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/avatar@0.0.8": {
+ "campgladiator.cgui/components/atoms/avatar@0.0.9": {
"files": [
{
"name": "Avatar.js",
@@ -115,7 +115,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/button@0.0.14": {
+ "campgladiator.cgui/components/atoms/button@0.0.15": {
"files": [
{
"name": "Button.js",
@@ -143,7 +143,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/callout@0.0.5": {
+ "campgladiator.cgui/components/atoms/callout@0.0.6": {
"files": [
{
"name": "Callout.js",
@@ -204,7 +204,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/checkbox@0.0.9": {
+ "campgladiator.cgui/components/atoms/checkbox@0.0.10": {
"files": [
{
"name": "Checkbox.js",
@@ -265,7 +265,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/dropdown@0.0.5": {
+ "campgladiator.cgui/components/atoms/dropdown@0.0.6": {
"files": [
{
"name": "Dropdown.js",
@@ -293,7 +293,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/fieldset@0.0.10": {
+ "campgladiator.cgui/components/atoms/fieldset@0.0.11": {
"files": [
{
"name": "Fieldset.js",
@@ -321,7 +321,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/form-label@0.0.10": {
+ "campgladiator.cgui/components/atoms/form-label@0.0.11": {
"files": [
{
"name": "FormLabel.js",
@@ -349,7 +349,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/growl@0.0.5": {
+ "campgladiator.cgui/components/atoms/growl@0.0.6": {
"files": [
{
"name": "Growl.js",
@@ -377,7 +377,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/heading@0.0.4": {
+ "campgladiator.cgui/components/atoms/heading@0.0.5": {
"files": [
{
"name": "Heading.js",
@@ -410,7 +410,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/icon@0.0.4": {
+ "campgladiator.cgui/components/atoms/icon@0.0.5": {
"files": [
{
"name": "Icon.js",
@@ -438,7 +438,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/image-label@0.0.4": {
+ "campgladiator.cgui/components/atoms/image-label@0.0.5": {
"files": [
{
"name": "ImageLabel.js",
@@ -466,7 +466,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/input@0.0.11": {
+ "campgladiator.cgui/components/atoms/input@0.0.12": {
"files": [
{
"name": "Input.js",
@@ -494,7 +494,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/loader@0.0.5": {
+ "campgladiator.cgui/components/atoms/loader@0.0.6": {
"files": [
{
"name": "Loader.js",
@@ -550,7 +550,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/progress-bar@0.0.8": {
+ "campgladiator.cgui/components/atoms/progress-bar@0.0.9": {
"files": [
{
"name": "ProgressBar.js",
@@ -583,7 +583,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/set-selector@0.0.5": {
+ "campgladiator.cgui/components/atoms/set-selector@0.0.6": {
"files": [
{
"relativePath": "src/components/atoms/SetSelector/SetSelector.js",
@@ -611,7 +611,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/slider@0.0.2": {
+ "campgladiator.cgui/components/atoms/slider@0.0.3": {
"files": [
{
"relativePath": "src/components/atoms/Slider/Slider.js",
@@ -644,7 +644,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/atoms/switch@0.0.4": {
+ "campgladiator.cgui/components/atoms/switch@0.0.5": {
"files": [
{
"name": "Switch.js",
@@ -672,7 +672,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/molecules/button-group@0.0.15": {
+ "campgladiator.cgui/components/molecules/button-group@0.0.16": {
"files": [
{
"name": "ButtonGroup.js",
@@ -700,7 +700,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/molecules/flash-message@0.0.3": {
+ "campgladiator.cgui/components/molecules/flash-message@0.0.4": {
"files": [
{
"relativePath": "src/components/molecules/FlashMessage/FlashMessage.js",
@@ -733,7 +733,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/molecules/modal@0.0.2": {
+ "campgladiator.cgui/components/molecules/modal@0.0.3": {
"files": [
{
"relativePath": "src/components/molecules/Modal/Modal.js",
@@ -766,7 +766,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/molecules/pin-input@0.0.2": {
+ "campgladiator.cgui/components/molecules/pin-input@0.0.3": {
"files": [
{
"relativePath": "src/components/molecules/PinInput/PinInput.js",
@@ -799,7 +799,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/molecules/radio-group@0.0.10": {
+ "campgladiator.cgui/components/molecules/radio-group@0.0.11": {
"files": [
{
"name": "RadioGroup.js",
@@ -827,7 +827,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/molecules/set-selector-group@0.0.5": {
+ "campgladiator.cgui/components/molecules/set-selector-group@0.0.6": {
"files": [
{
"relativePath": "src/components/molecules/SetSelectorGroup/SetSelectorGroup.js",
@@ -860,7 +860,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/molecules/steps@0.0.4": {
+ "campgladiator.cgui/components/molecules/steps@0.0.5": {
"files": [
{
"name": "Steps.js",
@@ -893,7 +893,7 @@
"origin": "AUTHORED",
"exported": true
},
- "campgladiator.cgui/components/molecules/tooltip@0.0.1": {
+ "campgladiator.cgui/components/molecules/tooltip@0.0.2": {
"files": [
{
"relativePath": "src/components/molecules/Tooltip/Tooltip.js",
diff --git a/src/App.js b/src/App.js
index 365fea2..7082a51 100644
--- a/src/App.js
+++ b/src/App.js
@@ -25,6 +25,7 @@ import ButtonGroup from './components/molecules/ButtonGroup'
import Steps from './components/molecules/Steps'
import Atoms from './examples/atoms'
import Molecules from './examples/molecules'
+import ProductImage from './components/atoms/ProductImage'
const toggleGrowl = () =>
document.getElementById('growlInfo') &&
@@ -341,6 +342,34 @@ function App() {
style={{ margin: '20px' }}
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/atoms/Avatar/Avatar.js b/src/components/atoms/Avatar/Avatar.js
index 124fc2c..c4dc62b 100644
--- a/src/components/atoms/Avatar/Avatar.js
+++ b/src/components/atoms/Avatar/Avatar.js
@@ -18,7 +18,7 @@ Avatar.defaultProps = {
alt: 'user image',
size: '48px',
className: '',
- style: '',
+ style: {},
}
Avatar.propTypes = {
diff --git a/src/components/atoms/ProductImage/ProductImage.js b/src/components/atoms/ProductImage/ProductImage.js
new file mode 100644
index 0000000..0575693
--- /dev/null
+++ b/src/components/atoms/ProductImage/ProductImage.js
@@ -0,0 +1,48 @@
+import React, { memo } from 'react'
+import PropTypes from 'prop-types'
+import './ProductImage.scss'
+
+const cdnBaseUrl =
+ 'https://cgcdn.s3.amazonaws.com/global-ui/images/Elements/Image'
+
+const defaultImages = {
+ bold: `${cdnBaseUrl}/Bold.png`,
+ single: `${cdnBaseUrl}/Single+Camp.png`,
+ owf: `${cdnBaseUrl}/One+Week+Free.png`,
+ default: `${cdnBaseUrl}/Image+Not+Available.png`,
+}
+
+const ProductImage = memo(
+ ({ src, type, alt, size, className, style, ...props }) => {
+ const imageSource = () =>
+ src ? src : type ? defaultImages[type] : defaultImages.default
+
+ return (
+
+ )
+ },
+)
+
+ProductImage.defaultProps = {
+ type: 'default',
+ size: '80px',
+ alt: 'product image',
+ className: '',
+ style: {},
+}
+
+ProductImage.propTypes = {
+ custom: PropTypes.string,
+ type: PropTypes.oneOf(['bold', 'single', 'owf', 'default']),
+ alt: PropTypes.string,
+ style: PropTypes.object,
+ className: PropTypes.string,
+}
+
+export default ProductImage
diff --git a/src/components/atoms/ProductImage/ProductImage.md b/src/components/atoms/ProductImage/ProductImage.md
new file mode 100644
index 0000000..c11d8df
--- /dev/null
+++ b/src/components/atoms/ProductImage/ProductImage.md
@@ -0,0 +1,13 @@
+Product Images are used primarily to serve the image shown at checkout for a specific product or service. This can show one of our default images (bold, single camp, one week free) or can show a custom image provided via the `src` prop.
+
+To use a default image, use the `type` prop by passing it a string of one of the following options:
+
+- `bold`: BOLD membership product
+- `single`: single camp membership product
+- `owf`: One week free product
+
+If no image is selected via the type or src props, the default "No image available" image will be used.
+
+Additionally, you can define the size of the image using the `size` prop. Default size is set to 80px X 80px.
+
+Product images should always have a 1:1 ratio and should ideally be served via our CDN rather than directly from the application source code/server.
diff --git a/src/components/atoms/ProductImage/ProductImage.scss b/src/components/atoms/ProductImage/ProductImage.scss
new file mode 100644
index 0000000..a3a8ca4
--- /dev/null
+++ b/src/components/atoms/ProductImage/ProductImage.scss
@@ -0,0 +1,6 @@
+@import '../../../assets/styles/variables.scss';
+
+.cg-product-image {
+ border: 2px solid $lighter-gray;
+ border-radius: 5px;
+}
diff --git a/src/components/atoms/ProductImage/ProductImage.spec.js b/src/components/atoms/ProductImage/ProductImage.spec.js
new file mode 100644
index 0000000..7847c26
--- /dev/null
+++ b/src/components/atoms/ProductImage/ProductImage.spec.js
@@ -0,0 +1,78 @@
+import React from 'react'
+import { shallow } from 'enzyme'
+import ProductImage from './ProductImage'
+
+const cdnBaseUrl =
+ 'https://cgcdn.s3.amazonaws.com/global-ui/images/Elements/Image'
+
+const defaultImages = {
+ bold: `${cdnBaseUrl}/Bold.png`,
+ single: `${cdnBaseUrl}/Single+Camp.png`,
+ owf: `${cdnBaseUrl}/One+Week+Free.png`,
+ default: `${cdnBaseUrl}/Image+Not+Available.png`,
+}
+
+const customImage =
+ 'https://en.gravatar.com/userimage/32884912/b318719acf13489f60cba203b71e4d15.png?size=200'
+
+describe('', () => {
+ it('renders without crashing', () => {
+ expect(() => shallow()).not.toThrow()
+ })
+
+ it('allows user-provided classes', () => {
+ expect(
+ shallow()
+ .find('.cg-product-image')
+ .hasClass('test-class'),
+ ).toBe(true)
+ })
+
+ it('renders with bold image', () => {
+ expect(
+ shallow()
+ .find('img')
+ .prop('src'),
+ ).toEqual(defaultImages.bold)
+ })
+
+ it('renders with single camp image', () => {
+ expect(
+ shallow()
+ .find('img')
+ .prop('src'),
+ ).toEqual(defaultImages.single)
+ })
+
+ it('renders with one week free image', () => {
+ expect(
+ shallow()
+ .find('img')
+ .prop('src'),
+ ).toEqual(defaultImages.owf)
+ })
+
+ it('renders with default image when no image is provided', () => {
+ expect(
+ shallow()
+ .find('img')
+ .prop('src'),
+ ).toEqual(defaultImages.default)
+ })
+
+ it('allows user-provided custom image', () => {
+ expect(
+ shallow()
+ .find('img')
+ .prop('src'),
+ ).toEqual(customImage)
+ })
+
+ it('allows user-provided alt text', () => {
+ expect(
+ shallow()
+ .find('img')
+ .prop('alt'),
+ ).toEqual('test alt text')
+ })
+})
diff --git a/src/components/atoms/ProductImage/index.js b/src/components/atoms/ProductImage/index.js
new file mode 100644
index 0000000..417d684
--- /dev/null
+++ b/src/components/atoms/ProductImage/index.js
@@ -0,0 +1 @@
+export { default } from './ProductImage'