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 ( + {alt} + ) + }, +) + +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'