Updated plop templates and added mobile first components

This commit is contained in:
2020-03-27 00:21:23 +05:30
parent 55737ad34d
commit 5ee96d6360
144 changed files with 2589 additions and 280 deletions

View File

@@ -0,0 +1,3 @@
.c-Button {
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './Button.component.scss'
const Button = props => {
return (
<div className='c-Button'>
</div>
);
};
Button.defaultProps = {
};
Button.propTypes = {
};
export default Button;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import Button from './Button';
describe('Button', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import Button from './Button.jsx';
export default Button;

View File

@@ -0,0 +1,15 @@
.c-InputField {
margin-bottom: 10px;
margin-top: 10px;
// label {
// float: left;
// display: flex;
// align-items: center;
// justify-content: center;
// margin-right: 10px;
// }
input[type="text"],input[type="password"] {
padding: 5px;
width: 70%;
}
}

View File

@@ -0,0 +1,69 @@
import React from 'react';
import PropTypes from 'prop-types';
const InputField = ({meta}) => {
return (
<div className='c-InputField'>
<div
className={`form-group row ${
meta.container_class ? meta.container_class : ''
}`}
aria-required={meta.aria_required}
>
<label htmlFor={meta.id} className="col-12 col-sm-3 col-lg-12 col-form-label">
{meta.validation.required.isRequired && !meta.isStandAloneField && (
<span className="required-indicator">* </span>
)}
{meta.label}
</label>
{meta.secondaryLabel ? (
<span className="field--label-description">{meta.secondaryLabel}</span>
) : null}
<div className="col-12 col-sm-9 col-12">
{meta.error && (
<span className="form-wrapper__field-error">{meta.errorMessage}</span>
)}
<input
className={`form-control ${meta.error ? 'error' : ''}`}
type={meta.type}
id={meta.id}
name={meta.name}
data-firstname="null"
value={
meta.fieldValues && meta.fieldValues.stateValue !== undefined
? meta.fieldValues.stateValue
: meta.fieldValues.propsValue
}
required={meta.validation.required.isRequired ? 'required' : ''}
minLength={meta.validation.rules.minlength}
maxLength={meta.validation.rules.maxlength}
placeholder={meta.placeholder}
aria-required={meta.aria_required}
aria-invalid={meta.aria_invalid}
// onFocus={onBlurProp ? onBlurProp : this.onFocusHandler}
onBlur={(e) =>
meta.handlers.onBlurHandler(
meta.validation,
meta.handlers.customBlurHandler,
e
)
}
onFocus={meta.handlers.onFocusHandler}
onChange={meta.handlers.onChangeHandler}
style={{width: '100%'}}
/>
</div>
</div>
</div>
);
};
InputField.defaultProps = {
};
InputField.propTypes = {
meta: PropTypes.object
};
export default InputField;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import InputField from './InputField';
describe('InputField', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import InputField from './InputField';
export default InputField;

View File

@@ -0,0 +1,3 @@
.c-SelectOption {
}

View File

@@ -0,0 +1,11 @@
import React from 'react';
import styles from './SelectOption.component.scss';
const SelectOption = props => {
return (
<div className={styles.root}>
</div>
);
};
export default SelectOption;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import SelectOption from './SelectOption';
describe('SelectOption', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import SelectOption from './SelectOption';
export default SelectOption;

View File

@@ -1,9 +1,47 @@
/* PLOP_INJECT_IMPORT */
import Header from './Header';
import PageLoader from './PageLoader';
import CartSummary from './molecules/CartSummary';
import CartItem from './molecules/CartItem';
import CartList from './molecules/CartList';
import Footer from './molecules/Footer';
import ProductTile from './molecules/ProductTile';
import ProductContainer from './molecules/ProductContainer';
import FilterModal from './molecules/FilterModal';
import SortModal from './molecules/SortModal';
import SortAndFilterPanel from './molecules/SortAndFilterPanel';
import CartIcon from './molecules/CartIcon';
import Search from './molecules/Search';
import Jumbotron from './molecules/common/Jumbotron';
import FormFieldContainer from './molecules/common/FormFieldContainer';
import Form from './molecules/common/Form';
import SocialLogin from './molecules/SocialLogin';
import LoginForm from './molecules/LoginForm';
import PageLoader from './molecules/PageLoader';
import Header from './molecules/Header'
import Button from './atoms/Button';
import InputField from './atoms/InputField';
import SelectOption from './atoms/SelectOption';
export {
/* PLOP_INJECT_EXPORT */
Header,
PageLoader
CartSummary,
CartItem,
CartList,
Footer,
ProductTile,
ProductContainer,
FilterModal,
SortModal,
Button,
SortAndFilterPanel,
CartIcon,
Search,
Jumbotron,
FormFieldContainer,
Form,
Header,
SocialLogin,
LoginForm,
SelectOption,
InputField,
PageLoader,
}

View File

@@ -0,0 +1,3 @@
.c-CartIcon {
}

View File

@@ -0,0 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
const CartIcon = props => {
return (
<div className='c-CartIcon'>
</div>
);
};
CartIcon.defaultProps = {
};
CartIcon.propTypes = {
};
export default CartIcon;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import CartIcon from './CartIcon';
describe('CartIcon', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import CartIcon from './CartIcon.jsx';
export default CartIcon;

View File

@@ -0,0 +1,3 @@
.c-CartItem {
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './CartItem.component.scss';
const CartItem = props => {
return (
<div className='c-CartItem'>
</div>
);
};
CartItem.defaultProps = {
};
CartItem.propTypes = {
};
export default CartItem;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import CartItem from './CartItem';
describe('CartItem', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import CartItem from './CartItem.jsx';
export default CartItem;

View File

@@ -0,0 +1,3 @@
.c-CartList {
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './CartList.component.scss';
const CartList = props => {
return (
<div className='c-CartList'>
</div>
);
};
CartList.defaultProps = {
};
CartList.propTypes = {
};
export default CartList;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import CartList from './CartList';
describe('CartList', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import CartList from './CartList.jsx';
export default CartList;

View File

@@ -0,0 +1,3 @@
.c-CartSummary {
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './CartSummary.component.scss';
const CartSummary = props => {
return (
<div className='c-CartSummary'>
</div>
);
};
CartSummary.defaultProps = {
};
CartSummary.propTypes = {
};
export default CartSummary;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import CartSummary from './CartSummary';
describe('CartSummary', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import CartSummary from './CartSummary.jsx';
export default CartSummary;

View File

@@ -0,0 +1,3 @@
.c-FilterModal {
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './FilterModal.component.scss';
const FilterModal = props => {
return (
<div className='c-FilterModal'>
</div>
);
};
FilterModal.defaultProps = {
};
FilterModal.propTypes = {
};
export default FilterModal;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import FilterModal from './FilterModal';
describe('FilterModal', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import FilterModal from './FilterModal.jsx';
export default FilterModal;

View File

@@ -0,0 +1,9 @@
.c-Footer {
position: fixed;
left: 0;
bottom: 0;
width: 100%;
background-color: #222;
color: white;
text-align: center;
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './Footer.component.scss';
const Footer = props => {
return (
<footer className='c-Footer'>
</footer>
);
};
Footer.defaultProps = {
};
Footer.propTypes = {
};
export default Footer;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import Footer from './Footer';
describe('Footer', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import Footer from './Footer.jsx';
export default Footer;

View File

@@ -1,10 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import Search from './../Search'
import CartIcon from './../CartIcon'
const Header = props => {
return (
<div className='c-Header'>
</div>
<header className='c-Header'>
<Search />
<CartIcon />
</header>
);
};

View File

@@ -1,3 +1,3 @@
import Header from './Header';
import Header from './Header.jsx';
export default Header;

View File

@@ -0,0 +1,3 @@
.c-LoginForm {
padding: 1rem;
}

View File

@@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import loginFormFields from './../../../config/forms-meta/login-form.json'
import Form from './../common/Form'
const LoginForm = props => {
return (
<div className='c-LoginForm'>
<Form
metaData={loginFormFields}
context="login"
updateFormValues={props.updateFormValues}
updateFormErrors={props.updateFormErrors}
formErrors={props.formErrors}
formValues={props.formValues}
/>
</div>
);
};
LoginForm.propTypes = {
updateFormValues: PropTypes.func,
updateFormErrors: PropTypes.func,
formValues: PropTypes.object,
formErrors: PropTypes.object
};
export default LoginForm;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import LoginForm from './LoginForm';
describe('LoginForm', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import LoginForm from './LoginForm';
export default LoginForm;

View File

@@ -0,0 +1,3 @@
.c-ProductContainer {
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './ProductContainer.component.scss';
const ProductContainer = props => {
return (
<div className='c-ProductContainer'>
</div>
);
};
ProductContainer.defaultProps = {
};
ProductContainer.propTypes = {
};
export default ProductContainer;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import ProductContainer from './ProductContainer';
describe('ProductContainer', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import ProductContainer from './ProductContainer.jsx';
export default ProductContainer;

View File

@@ -0,0 +1,3 @@
.c-ProductTile {
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './ProductTile.component.scss';
const ProductTile = props => {
return (
<div className='c-ProductTile'>
</div>
);
};
ProductTile.defaultProps = {
};
ProductTile.propTypes = {
};
export default ProductTile;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import ProductTile from './ProductTile';
describe('ProductTile', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import ProductTile from './ProductTile.jsx';
export default ProductTile;

View File

@@ -0,0 +1,3 @@
.c-Search {
}

View File

@@ -0,0 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
const Search = props => {
return (
<div className='c-Search'>
</div>
);
};
Search.defaultProps = {
};
Search.propTypes = {
};
export default Search;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import Search from './Search';
describe('Search', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import Search from './Search.jsx';
export default Search;

View File

@@ -0,0 +1,10 @@
.c-SocialLogin {
padding: 1rem;
margin-bottom: 2rem;
display: flex;
justify-content: center;
.abcRioButtonBlue {
background: white;
color: #585f6b;
}
}

View File

@@ -0,0 +1,68 @@
import React from 'react';
import {withRouter} from 'react-router-dom'
import {gapi} from 'gapi-script'
class SocialLogin extends React.Component{
constructor(props) {
super(props)
this.width = 254
this.height = 50
this.onSuccess = this.onSuccess.bind(this)
this.onFailure = this.onFailure.bind(this)
}
componentDidMount() {
gapi && gapi.signin2 && gapi.signin2.render('g-signin2', {
'scope': 'profile email',
'width': this.width,
'height': this.height,
'longtitle': true,
'theme': 'dark',
'onsuccess': this.onSuccess,
'onfailure': this.onFailure
});
}
onSuccess(googleUser) {
console.log('Logged in as: ' + googleUser.getBasicProfile().getName());
this.props.history.push('/view/plp')
}
onFailure(error) {
console.log(error);
}
render() {
return (
<div className='c-SocialLogin'>
<div className="row">
<div className="col-12">
<div className="g-signin2" id="g-signin2"></div>
</div>
<div className="col-12">
<div
className="fb-login-button"
data-width={this.width}
data-height={this.height}
data-size="large"
data-button-type="continue_with"
data-auto-logout-link="false"
data-use-continue-as="true"
/>
</div>
</div>
</div>
);
}
}
SocialLogin.defaultProps = {
};
SocialLogin.propTypes = {
};
export default withRouter(SocialLogin)

View File

@@ -0,0 +1,8 @@
import React from 'react';
import SocialLogin from './SocialLogin';
describe('SocialLogin', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import SocialLogin from './SocialLogin.jsx';
export default SocialLogin;

View File

@@ -0,0 +1,3 @@
.c-SortAndFilterPanel {
}

View File

@@ -0,0 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
const SortAndFilterPanel = props => {
return (
<div className='c-SortAndFilterPanel'>
</div>
);
};
SortAndFilterPanel.defaultProps = {
};
SortAndFilterPanel.propTypes = {
};
export default SortAndFilterPanel;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import SortAndFilterPanel from './SortAndFilterPanel';
describe('SortAndFilterPanel', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import SortAndFilterPanel from './SortAndFilterPanel.jsx';
export default SortAndFilterPanel;

View File

@@ -0,0 +1,3 @@
.c-SortModal {
}

View File

@@ -0,0 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './SortModal.component.scss';
const SortModal = props => {
return (
<div className='c-SortModal'>
</div>
);
};
SortModal.defaultProps = {
};
SortModal.propTypes = {
};
export default SortModal;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import SortModal from './SortModal';
describe('SortModal', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import SortModal from './SortModal.jsx';
export default SortModal;

View File

@@ -0,0 +1,7 @@
.c-Form {
padding: 15px;
background: #ddd;
border: 1px solid #bbb;
border-radius: 3px;
margin-top: 10px;
}

View File

@@ -0,0 +1,91 @@
import React from 'react'
import PropTypes from 'prop-types'
import FormFieldContainer from '../FormFieldContainer';
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
name: '',
greeting: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.onFocusHandler = this.onFocusHandler.bind(this)
}
handleChange(event) {
this.setState({ name: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
// fetch(`/api/greeting?name=${encodeURIComponent(this.state.name)}`)
// .then(response => response.json())
// .then(state => this.setState(state));
}
onFocusHandler() {
console.log('Parent, on focus handler')
}
render() {
const {
context,
fieldValues,
formErrors,
formValues,
metaData,
updateFormErrors,
updateFormValues
} = this.props
// const jsonData = this.props && this.props.metaData
const inputList = metaData && context ? Object.keys(metaData[context]) : []
let inputListSection =
inputList &&
inputList.map((item, index) => {
const formFieldObject = metaData[context][item]
const formField = formFieldObject ? (
<FormFieldContainer
propsData={formFieldObject}
key={index}
onFocus={this.onFocusHandler}
value={fieldValues && fieldValues[item]}
formErrors={formErrors}
formValues={formValues}
updateFormErrors={updateFormErrors}
updateFormValues={updateFormValues}
/>
) : null
return formField
})
inputListSection = inputListSection.filter((formFieldObject) => {
return formFieldObject !== null
})
return (
<form className='c-Form' onSubmit={this.handleSubmit}>
<fieldset>{inputListSection}</fieldset>
<button type="submit" className="btn btn-primary btn-block" style={{marginTop: '15px', background: 'black'}}>Submit</button>
</form>
)
}
}
Form.propTypes = {
context: PropTypes.string,
customBlurHandler: PropTypes.func,
customBlurFormatter: PropTypes.func,
metaData: PropTypes.object.isRequired,
className: PropTypes.string,
fieldValues: PropTypes.object,
formErrors: PropTypes.object,
formValues: PropTypes.object,
updateFormErrors: PropTypes.func,
updateFormValues: PropTypes.func
}
export default Form

View File

@@ -0,0 +1,8 @@
import React from 'react';
import Form from './Form';
describe('Form', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import Form from './Form';
export default Form;

View File

@@ -0,0 +1,3 @@
.c-FormFieldContainer {
}

View File

@@ -0,0 +1,252 @@
import React from 'react'
import PropTypes from 'prop-types'
import InputField from '../../../atoms/InputField'
import SelectOption from '../../../atoms/SelectOption'
/**
* INSERT_DESCRIPTION_HERE
*/
class FormFieldContainer extends React.Component {
constructor(props) {
super(props)
const componentKey = this.props.propsData && this.props.propsData.id
const passedValue = this.props.value || (this.props.propsData && this.props.propsData.value)
this.state = {
error: false,
errorMessage: null
}
this.props.updateFormValues({
formValues: {
// ...this.props.formValues,
[componentKey]: passedValue ? passedValue : ''
}
})
this.props.updateFormErrors({
formErrors: {
// ...this.props.formErrors,
[componentKey]: ''
}
})
this.customExecutes = this.customExecutes.bind(this)
this.prepareCVN = this.prepareCVN.bind(this)
this.executeDateValidations = this.executeDateValidations.bind(this)
this.onChangeHandler = this.onChangeHandler.bind(this)
this.onBlurHandler = this.onBlurHandler.bind(this)
this.onFocusHandler = this.onFocusHandler.bind(this)
}
/**
* validateFormField - validates the input field values
* @param {object} event js event object
* @param {object} validationObj fieldinput data as props
*/
validateFormField(e, validationObj) {
const {propsData, formErrors, formValues, updateFormErrors, updateFormValues} = this.props
const inputValue = e.target.value && e.target.value
let error = false
let errorMessage = ''
const componentKey = propsData.id
const validRegex =
validationObj.dataRuleRegex &&
new RegExp(validationObj.dataRuleRegex.regex).test(inputValue)
const poValidRegex =
e.target.id === 'address1' &&
validationObj.dataRuleRegex.po_regex &&
new RegExp(validationObj.dataRuleRegex.po_regex, 'i').test(inputValue)
if (e.target.tagName && e.target.tagName === 'SELECT') {
if (
validationObj.required.isRequired &&
e.target.selectedIndex === 0 &&
!validationObj.required.preSelected
) {
error = true
errorMessage = validationObj.required.error_message
}
} else if (e.target.tagName && e.target.tagName === 'INPUT') {
if (validationObj.required.isRequired) {
if (inputValue.trim('') === '') {
error = true
errorMessage = validationObj.required.error_message
} else if (validationObj.dataRuleRegex && !validRegex) {
error = true
errorMessage = validationObj.dataRuleRegex.error_message
} else if (validationObj.dataRuleRegex && poValidRegex) {
error = true
errorMessage = validationObj.dataRuleRegex.po_error_message
}
}
} else {
error = false
errorMessage = null
}
if (!errorMessage && propsData.id === 'expiration_month') {
errorMessage = this.executeDateValidations()
if (errorMessage) {
error = true
}
}
this.setState({
error
})
updateFormErrors({
formErrors: {
...formErrors,
[componentKey]: errorMessage
}
})
updateFormValues({
formValues: {
...formValues,
[componentKey]: inputValue
}
})
return error
}
onChangeHandler(event) {
const value = event.target.value
this.setState({
value
})
this.executeDateValidations(event)
}
onFocusHandler(event) {
this.setState({
oldValue: event.target.value
})
}
onBlurHandler(validation, customBlurHandler, e) {
e.oldValue = this.state.oldValue
const {customBlurFormatter} = this.props
const isError = this.validateFormField(e, validation)
if (!isError) {
if (customBlurHandler && typeof customBlurHandler === 'function') {
customBlurHandler(e)
}
if (customBlurFormatter && typeof customBlurFormatter === 'function') {
this.setState({value: customBlurFormatter(e)})
}
}
}
prepareCVN() {
const {propsData, selectedCreditCard} = this.props
if (propsData && propsData.ccNumberUpdated !== undefined && propsData.ccNumberUpdated) {
this.setState({
value: ''
})
this.props.updateFormValues({
formValues: {
...this.props.formValues,
security_code: ''
}
})
propsData.ccNumberUpdated = false
}
if (selectedCreditCard) {
if (selectedCreditCard.payment_card.card_type === 'Amex') {
propsData.validation.dataRuleRegex.regex = /^[0-9'\s]{4}$/
propsData.validation.rules.maxlength = 4
} else {
propsData.validation.dataRuleRegex.regex = /^[0-9'\s]{3}$/
propsData.validation.rules.maxlength = 3
}
}
}
executeDateValidations(event) {
const {propsData, formValues, formErrors, updateFormErrors} = this.props
let errorMessage = ''
if (propsData.id === 'expiration_month' || propsData.id === 'expiration_year') {
let month = ''
let year = ''
if (propsData.id === 'expiration_month') {
month = +event.target.value
year = +formValues.expiration_year
} else if (propsData.id === 'expiration_year') {
month = +formValues.expiration_month
year = +event.target.value
}
const currentYear = new Date().getFullYear()
const currentMonth = new Date().getMonth()
if (year === currentYear && month < currentMonth + 1) {
errorMessage = 'This Credit Card is expired'
} else {
errorMessage = ''
}
updateFormErrors({
formErrors: {
...formErrors,
expiration_month: errorMessage
}
})
}
return errorMessage
}
customExecutes() {
this.prepareCVN()
}
render() {
const {customBlurHandler, formErrors, propsData} = this.props
const {elementType} = propsData
const errorMessage = formErrors && formErrors[propsData.id]
this.customExecutes()
const meta = {
...this.props.propsData,
className: this.state.error ? 'error' : '',
error: this.state.error || errorMessage,
errorMessage,
handlers: {
onBlurHandler: this.onBlurHandler,
customBlurHandler,
onChangeHandler: this.onChangeHandler,
onFocusHandler: this.onFocusHandler
},
fieldValues: {
propsValue: this.props.value,
stateValue: this.state.value
}
}
/**
* switch function - returns HTML Tag depending upon the requirement
* @param {string} elementType - element type e.g. input,select
*/
switch (elementType) {
case 'input':
return <InputField meta={meta} />
case 'select':
return <SelectOption meta={meta} />
default:
return <input />
}
}
}
FormFieldContainer.propTypes = {
propsData: PropTypes.object.isRequired,
className: PropTypes.string,
customBlurHandler: PropTypes.func,
customBlurFormatter: PropTypes.func,
onFocus: PropTypes.func,
value: PropTypes.string,
formValues: PropTypes.object,
formErrors: PropTypes.object,
selectedCreditCard: PropTypes.object,
updateFormValues: PropTypes.func,
updateFormErrors: PropTypes.func
}
export default FormFieldContainer

View File

@@ -0,0 +1,8 @@
import React from 'react';
import FormFieldContainer from './FormFieldContainer';
describe('FormFieldContainer', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import FormFieldContainer from './FormFieldContainer';
export default FormFieldContainer;

View File

@@ -0,0 +1,9 @@
.c-Jumbotron {
padding: 1rem;
background: #222;
color: #bbbbbb;
margin-bottom: 0;
.my-4 {
border-color: #bbb;
}
}

View File

@@ -0,0 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types'
import {Link} from 'react-router-dom'
const Jumbotron = props => {
return (
<div className='c-Jumbotron'>
<h1 className="display-4">{props.jumboText}</h1>
<p className="lead">{props.subText}</p>
<hr className='my-4' />
<p>{props.jumboDescription}</p>
<p className="lead">
<Link className="btn btn-primary btn-lg" to="/view/plp" role="button">Go To PLP</Link>
<Link className="btn btn-primary btn-lg float-right" to="#" role="button" style={{marginLeft: '15px'}}>{props.furtherLink}</Link>
</p>
</div>
);
};
Jumbotron.propTypes = {
furtherLink: PropTypes.string,
jumboDescription: PropTypes.string,
jumboText: PropTypes.string,
subText: PropTypes.string
};
export default Jumbotron;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import Jumbotron from './Jumbotron.jsx';
describe('Jumbotron', () => {
it('renders without error', () => {
});
});

View File

@@ -0,0 +1,3 @@
import Jumbotron from './Jumbotron.jsx';
export default Jumbotron;

View File

@@ -0,0 +1,37 @@
{
"login": {
"email": {
"label": "Email ID",
"placeholder": "Email ID",
"type": "text",
"id": "email",
"elementType": "input",
"validation": {
"required": {
"isRequired": "true",
"error_message": "This field is required."
},
"rules": {
"minlength": 6,
"maxlength": 50
}
}
},
"password": {
"label": "Password",
"placeholder": "Password",
"type": "password",
"id": "password",
"elementType": "input",
"validation": {
"required": {
"isRequired": "true",
"error_message": "This field is required."
},
"rules": {
}
}
}
}
}

View File

@@ -2,8 +2,9 @@
@import 'styles/variables';
@import 'styles/base';
@import 'styles/components';
@import 'styles/utilities';
@import 'styles/pages';
@import 'styles/components';
.abcRioButtonBlue {
background-color: white!important;

View File

@@ -6,8 +6,8 @@ import {createStore, applyMiddleware, compose} from 'redux'
// import * as serviceWorker from '../serviceWorker';
import Router from './router';
import reducer from './reducer'
import 'bootstrap/dist/css/bootstrap.min.css'
import './index.scss'
import 'bootstrap/dist/css/bootstrap.min.css'
const composeEnhancers =
typeof window === 'object' &&

View File

@@ -1,21 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './Login.module.scss';
const Login = props => {
return (
<div className={styles.root}>
<p>This is the login module</p>
</div>
);
};
Login.defaultProps = {
};
Login.propTypes = {
};
export default Login;

View File

@@ -0,0 +1,84 @@
import React from 'react'
import PropTypes from 'prop-types'
import styles from './Login.module.scss'
import {connect} from 'react-redux'
import {createPropsSelector} from 'reselect-immutable-helpers'
import * as actions from './actions'
import {getLogin, getFormErrors, getFormValues} from './selectors'
import LoginForm from '../../components/molecules/LoginForm'
import SocialLogin from '../../components/molecules/SocialLogin'
import Jumbotron from '../../components/molecules/common/Jumbotron'
class Login extends React.Component {
constructor(props) {
super(props)
this.pageType = 'login'
}
componentDidMount() {
const {initializeLogin} = this.props
initializeLogin()
}
clicked() {
console.log('login handler')
}
render() {
const {updateFormErrors, updateFormValues, formErrors, formValues} = this.props
return (
<div className={`${styles.Login} container`} onClick={this.clicked}>
<div className="row">
<div className="col-12 col-lg-8">
<Jumbotron
jumboText="Adobe - Joules to Watts assignment"
subText="PLP and Cart Page Demo"
jumboDescription="This app is build using React JS and routing is added using custom solutions to work on GH Pages. Login is optional and can be skipped."
furtherLink="Learn more"
/>
</div>
<div className="col-12 col-lg-4">
<div className={styles.loginContainer}>
<p className={styles['c-login-intimation']}>Let's get to know each other, shall we!</p>
<LoginForm
updateFormValues={updateFormValues}
updateFormErrors={updateFormErrors}
formErrors={formErrors}
formValues={formValues}
/>
<p className={styles.loginSplitter}>OR</p>
<SocialLogin />
</div>
</div>
</div>
</div>
)
}
}
Login.propTypes = {
initializeLogin: PropTypes.func,
dataState: PropTypes.object,
updateFormValues: PropTypes.func,
updateFormErrors: PropTypes.func,
formValues: PropTypes.object,
formErrors: PropTypes.object
}
const mapStateToProps = createPropsSelector({
dataState: getLogin,
formErrors: getFormErrors,
formValues: getFormValues
})
const mapDispatchToProps = {
initializeLogin: actions.initializeLogin,
updateFormErrors: actions.updateFormErrors,
updateFormValues: actions.updateFormValues
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Login)

View File

@@ -1,3 +1,32 @@
.c-Login {
.Login {
background: #222;
max-width: unset;
@media only screen and (max-width: 1140px) {
padding-left: unset;
padding-right: unset;
margin-right: unset;
margin-left: unset;
}
.loginContainer {
border: 2px solid grey;
border-radius: 0.3rem;
margin: 1rem;
background: #eee;
padding-bottom: 20px;
.c-login-intimation {
padding: 15px 5px 15px 15px;
background: black;
color: white;
margin-bottom: 0;
}
.loginSplitter {
text-align: center;
margin-top: 10px;
margin-bottom: 10px;
text-transform: capitalize;
font-size: 25px;
font-weight: bolder;
line-height: 30px;
}
}
}

View File

@@ -1,3 +1,3 @@
import Login from './Login';
import Login from './Login.jsx';
export default Login;

View File

@@ -1,20 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './Plp.module.scss';
const Plp = props => {
return (
<div className={styles.root}>
</div>
);
};
Plp.defaultProps = {
};
Plp.propTypes = {
};
export default Plp;

29
src/app/pages/PLP/Plp.jsx Normal file
View File

@@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './Plp.module.scss';
import Header from './../../components/molecules/Header'
import SortAndFilterPanel from './../../components/molecules/SortAndFilterPanel'
import ProductContainer from './../../components/molecules/ProductContainer'
import Footer from './../../components/molecules/Footer'
const Plp = props => {
return (
<div className={styles.root}>
<Header />
<SortAndFilterPanel />
<ProductContainer />
<Footer />
</div>
);
};
Plp.defaultProps = {
};
Plp.propTypes = {
};
export default Plp;

View File

@@ -1,3 +1,3 @@
import Plp from './Plp';
import Plp from './Plp.jsx';
export default Plp;

View File

@@ -1,5 +1,8 @@
@import 'base/animations';
@import 'base/forms';
@import 'base/general';
@import 'base/lists';
@import 'base/material';
@import 'base/mixins';
@import 'base/tables';
@import 'base/typography';

View File

@@ -1,5 +1,13 @@
// Components
// ===
// @import '../components/atoms/InputField/InputField.component';
@import '../components/atoms/InputField/InputField.component';
@import '../components/atoms/SelectOption/SelectOption.component';
@import '../components/molecules/common/Form/Form.component';
@import '../components/molecules/common/FormFieldContainer/FormFieldContainer.component';
@import '../components/molecules/common/Jumbotron/Jumbotron.component';
@import '../components/molecules/Header/Header.component';
@import '../components/molecules/LoginForm/LoginForm.component';
@import '../components/molecules/PageLoader/PageLoader.component';
@import '../components/molecules/SocialLogin/SocialLogin.component';
// @import '../preloader/preload';

View File

@@ -0,0 +1,25 @@
// Utilities
// ===
//
// Use wrap-at-root mixin to allow overriding existing styles with extreme
// specificity while keeping source code clean and readable. Does not override
// !important or inline styles; those must be dealt with separately.
@import 'base/mixins';
@include wrap-at-root("#app", 1) {
@import 'utilities/border';
@import 'utilities/box-shadow';
@import 'utilities/color';
@import 'utilities/flexbox';
@import 'utilities/heading';
@import 'utilities/layout';
@import 'utilities/margin';
@import 'utilities/padding';
@import 'utilities/text-content';
@import 'utilities/text';
@import 'utilities/display';
@import 'utilities/visibility';
@import 'utilities/z-index';
}

View File

@@ -115,6 +115,7 @@ $bold-font-weight: 700;
// Neutrals
$neutral-00: #fff;
$neutral-10: #f7f7f7;
$neutral-12: #f1f3f6;
$neutral-15: #eee;
$neutral-20: #d5d5d5;
$neutral-30: #bfbfbf;
@@ -124,8 +125,10 @@ $neutral-60: #333;
$neutral-70: #000;
// Brand colors
$brand-color: #017e9b; // blue
$secondary-brand-color: #005569;
// $brand-color: #017e9b; // blue
$brand-color: #4471ea; // blue
// $secondary-brand-color: #005569;
$secondary-brand-color: #fafafa;
$tertiary-brand-color: #83bdcb;
$quaternary-brand-color: #bfdfe6;
@@ -175,6 +178,7 @@ $yelp-color: #af0606;
// ---
$font-color: $neutral-60;
$font-color-light: #b8b8b8;
$link-color: $ui-brand-color;
$active-link-color: $dark-accent-color;
@@ -193,7 +197,7 @@ $disabled-button-background-color: $neutral-15;
$horizontal-input-padding: $unit;
$vertical-input-padding: $unit;
$background-color: $neutral-10;
$background-color: $neutral-12;
$overlay-color: rgba($neutral-00, 0.85);

View File

@@ -0,0 +1,15 @@
// Animations
// ===
//
// Background Shimmer
// ---
@keyframes background-shimmer {
0% {
background-position: 150vw 0;
}
100% {
background-position: -150vw 0;
}
}

View File

@@ -33,6 +33,7 @@ html {
body {
margin: 0;
background-color: #222!important;
}
// Grouping content

View File

@@ -0,0 +1,26 @@
// Tables
// ===
table {
border-spacing: 0;
border-collapse: collapse;
width: 100%;
margin: $unit 0;
}
th {
padding: $unit 0;
font-weight: $semi-bold-font-weight;
text-align: left;
}
td {
padding: $unit 0;
}
tr,
td,
th {
vertical-align: middle;
}

View File

@@ -0,0 +1,61 @@
// Border
// ===
// Border (Width and Color)
// ---
.u-border {
border: $border;
}
.u-border-0 {
border: 0;
}
.u-border-top {
border-top: $border;
}
.u-border-end {
border-right: $border;
}
.u-border-bottom {
border-bottom: $border;
}
.u-border-start {
border-left: $border;
}
// Light Border (Width and Color)
// ---
.u-border-light {
border: $light-border;
}
.u-border-light-top {
border-top: $light-border;
}
.u-border-light-end {
border-right: $light-border;
}
.u-border-light-bottom {
border-bottom: $light-border;
}
.u-border-light-start {
border-left: $light-border;
}
// Border (Other)
// ---
.u-border-radius {
border-radius: $border-radius;
}

View File

@@ -0,0 +1,18 @@
// Box Shadow
// ===
.u-box-shadow {
box-shadow: $box-shadow;
}
.u-box-shadow-inset {
box-shadow: $inset-box-shadow;
}
.u-box-shadow-lg {
box-shadow: $large-box-shadow;
}
.u-box-shadow-input {
box-shadow: $input-box-shadow;
}

View File

@@ -0,0 +1,177 @@
// Color
// ===
// Neutral Colors
// ---
.u-color-neutral-00 {
color: $neutral-00;
fill: $neutral-00;
}
.u-color-neutral-10 {
color: $neutral-10;
fill: $neutral-10;
}
.u-color-neutral-15 {
color: $neutral-15;
fill: $neutral-15;
}
.u-color-neutral-20 {
color: $neutral-20;
fill: $neutral-20;
}
.u-color-neutral-30 {
color: $neutral-30;
fill: $neutral-30;
}
.u-color-neutral-40 {
color: $neutral-40;
fill: $neutral-40;
}
.u-color-neutral-50 {
color: $neutral-50;
fill: $neutral-50;
}
.u-color-neutral-60 {
color: $neutral-60;
fill: $neutral-60;
}
.u-color-neutral-70 {
color: $neutral-70;
fill: $neutral-70;
}
// Other Colors
// ---
.u-color-brand {
color: $brand-color;
fill: $brand-color;
}
.u-color-accent {
color: $accent-color;
fill: $accent-color;
}
.u-color-primary-action {
color: $primary-action-color;
fill: $primary-action-color;
}
.u-color-secondary-action {
color: $secondary-action-color;
fill: $secondary-action-color;
}
.u-color-success {
color: $success-color;
fill: $success-color;
}
.u-color-error {
color: $error-color;
fill: $error-color;
}
.u-color-sale {
color: $sale-color;
fill: $sale-color;
}
// Background Colors
// ---
.u-bg-color-neutral-00 {
background-color: $neutral-00;
}
.u-bg-color-neutral-10 {
background-color: $neutral-10;
}
.u-bg-color-neutral-15 {
background-color: $neutral-15;
}
.u-bg-color-neutral-20 {
background-color: $neutral-20;
}
.u-bg-color-neutral-30 {
background-color: $neutral-30;
}
.u-bg-color-neutral-40 {
background-color: $neutral-40;
}
.u-bg-color-neutral-50 {
background-color: $neutral-50;
}
.u-bg-color-neutral-60 {
background-color: $neutral-60;
}
.u-bg-color-neutral-70 {
background-color: $neutral-70;
}
// Other Background Colors
// ---
.u-bg-color-brand {
background-color: $brand-color;
}
.u-bg-color-accent {
background-color: $accent-color;
}
.u-bg-color-primary-action {
background-color: $primary-action-color;
}
.u-bg-color-secondary-action {
background-color: $secondary-action-color;
}
.u-bg-color-success {
background-color: $success-color;
}
.u-bg-color-error {
background-color: $error-color;
}
.u-bg-color-sale {
background-color: $sale-color;
}

View File

@@ -0,0 +1,42 @@
// Display
// ===
// Display: Block
// ---
.u-display-block {
display: block;
}
// Display: Inline Block
// ---
.u-display-inline-block {
display: inline-block;
}
// Display: Inline
// ---
.u-display-inline {
display: inline;
}
// Dispaly: Inline Table
// ---
.u-display-inline-table {
display: inline-table;
}
// Display: None
// ---
.u-display-none {
display: none;
}

Some files were not shown because too many files have changed in this diff Show More