Skip to content

Commit

Permalink
feat(addresscapture): container for AddressForm & AddressReview
Browse files Browse the repository at this point in the history
  • Loading branch information
nnnnat committed Nov 14, 2018
1 parent 4173da7 commit da5eb69
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 0 deletions.
113 changes: 113 additions & 0 deletions package/src/components/AddressCapture/v1/AddressCapture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import { withComponents } from "@reactioncommerce/components-context";
import { CustomPropTypes } from "../../../utils";

class AddressCapture extends Component {
static propTypes = {
addressFormProps: PropTypes.shape({
addressNamePlaceholder: PropTypes.string,
shouldShowAddressNameField: PropTypes.bool,
shouldShowIsCommercialField: PropTypes.bool,
value: CustomPropTypes.address
}),
addressReviewProps: PropTypes.shape({
addressEntered: CustomPropTypes.address,
addressSuggestion: CustomPropTypes.address,
value: PropTypes.string
}),
/**
* You can provide a `className` prop that will be applied to the outermost DOM element
* rendered by this component. We do not recommend using this for styling purposes, but
* it can be useful as a selector in some situations.
*/
className: PropTypes.string,
/**
* If you've set up a components context using
* [@reactioncommerce/components-context](https://github.com/reactioncommerce/components-context)
* (recommended), then this prop will come from there automatically. If you have not
* set up a components context or you want to override one of the components in a
* single spot, you can pass in the components prop directly.
*/
components: PropTypes.shape({
/**
* Pass either the Reaction AddressForm component or your own component that is
* compatible with the AddressForm spec.
*/
AddressForm: CustomPropTypes.component.isRequired,
/**
* Pass either the Reaction AddressReview component or your own component that is
* compatible with AddressReview spec.
*/
AddressReview: CustomPropTypes.component.isRequired
}).isRequired,
isSaving: PropTypes.bool,
name: PropTypes.string,
onAddressValidation: PropTypes.func,
onSubmit: PropTypes.func
};

static defaultProps = {
addressFormProps: {},
addressReviewProps: {
addressSuggestion: null
},
isSaving: false
};

_form = null;

/**
*
* @name submit
* @summary Instance method that submits the form, this allows a parent component access to the Form submit event.
* @return {Undefined} - Nothing
*/
submit = () => {
this._form.submit();
};

handleSubmit = async (address) => {
const { onAddressValidation, onSubmit } = this.props;
if (onAddressValidation && !address.isValid) {
await onAddressValidation(address);
} else {
await onSubmit(address);
}
};

renderForm() {
const { addressFormProps, components: { AddressForm }, isSaving } = this.props;
return (
<AddressForm
{...addressFormProps}
ref={(el) => {
this._form = el;
}}
isSaving={isSaving}
onSubmit={this.handleSubmit}
/>
);
}

renderReview() {
const { addressReviewProps, components: { AddressReview }, isSaving } = this.props;
return (
<AddressReview
{...addressReviewProps}
ref={(el) => {
this._form = el;
}}
isSaving={isSaving}
onSubmit={this.handleSubmit}
/>
);
}

render() {
const { addressReviewProps: { addressSuggestion }, className } = this.props;
return <div className={className}>{addressSuggestion ? this.renderReview() : this.renderForm()}</div>;
}
}

export default withComponents(AddressCapture);
141 changes: 141 additions & 0 deletions package/src/components/AddressCapture/v1/AddressCapture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
### Overview

### Usage

#### Add an address
```jsx
initialState = { isProcessing: false, savedAddress: null };
let _form = null;

const handleSubmit = (value) => new Promise((resolve, reject) => {
setState({ isProcessing: true });
setTimeout(async () => {
console.log("Address saved", value);
setState({ isProcessing: false, savedAddress: value });
resolve(value)
}, 2000);
});

const props = {
addressFormProps: {
shouldShowIsCommercialField: true,
value: state.savedAddress
},
name: "example",
onSubmit: handleSubmit
};

state.savedAddress ? <Address address={state.savedAddress} /> : <div>
<AddressCapture {...props} ref={(formEl) => { _form = formEl; }} />
<Button onClick={() => { _form.submit() }} isWaiting={state.isProcessing}>Capture</Button>
</div>
```

#### Edit an address
```jsx
initialState = {
isProcessing: false,
updatedAddress: null,
savedAddress: {
address1: "2110 Main Street",
address2: "Suite 207",
country: "US",
city: "Santa Monica",
fullName: "Reaction Commerce, Inc.",
postal: "90405",
region: "CA",
phone: "123-123-1234",
isCommercial: true
}
};
let _form = null;

const handleSubmit = (value) => new Promise((resolve, reject) => {
setState({ isProcessing: true });
setTimeout(async () => {
console.log("Address saved", value);
setState({ isProcessing: false, updatedAddress: value });
resolve(value)
}, 2000);
});

const props = {
addressFormProps: {
shouldShowIsCommercialField: true,
value: state.updatedAddress || state.savedAddress
},
name: "example",
onSubmit: handleSubmit
};

console.log("whats the saved address", state.savedAddress);

state.updatedAddress ? <Address address={state.updatedAddress} /> : <div>
<AddressCapture {...props} ref={(formEl) => { _form = formEl; }} />
<Button onClick={() => { _form.submit() }} isWaiting={state.isProcessing}>Edit</Button>
</div>
```

#### Validate an address
```jsx
initialState = { isProcessing: false, savedAddress: null, submittedAddress: null, validationResults: null };
let _form = null;

const handleSubmit = (value) => new Promise((resolve, reject) => {
setState({ isProcessing: true });
setTimeout(async () => {
console.log("Address saved", value);
setState({ isProcessing: false, savedAddress: value });
resolve(value)
}, 2000);
});

const handleAddressValidation = (value) => new Promise((resolve, reject) => {
setState({ isProcessing: true, submittedAddress: value });
setTimeout(async () => {
console.log("Address validated", value);
const validationResults = {
suggestedAddresses: [{
...value,
address1: "Corrected " + value.address1,
postal: "90210",
isValid: true
}],
validationErrors: [{
summary: "Address Not Found",
details: "The address as submitted could not be found. Please check for excessive abbreviations in " +
"the street address line or in the City name.",
source: "USPS",
type: "error"
}]
};
setState({ isProcessing: false, validationResults });
resolve(value);
}, 2000);
});

const props = {
addressFormProps: {
shouldShowIsCommercialField: true,
value: state.submittedAddress
},
addressReviewProps: {
addressEntered: state.submittedAddress,
addressSuggestion: state.validationResults && state.validationResults.suggestedAddresses[0] || null
},
name: "example",
onSubmit: handleSubmit,
onAddressValidation: handleAddressValidation
};

state.savedAddress ? <Address address={state.savedAddress} /> : <div>
<AddressCapture {...props} ref={(formEl) => { _form = formEl; }} />
<Button onClick={() => { _form.submit() }} isWaiting={state.isProcessing}>{state.validationResults ? "Capture" : "Validate"}</Button>
</div>
```

### Theme

Assume that any theme prop that does not begin with "rui" is within `rui_components`. See [Theming Components](./#!/Theming%20Components).

| Theme Prop | Default | Description |
11 changes: 11 additions & 0 deletions package/src/components/AddressCapture/v1/AddressCapture.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from "react";
import renderer from "react-test-renderer";
import mockComponents from "../../../tests/mockComponents";
import AddressCapture from "./AddressCapture";

test("basic snapshot", () => {
const component = renderer.create(<AddressCapture components={mockComponents} />);

const tree = component.toJSON();
expect(tree).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`basic snapshot 1`] = `
<div
className={undefined}
>
AddressForm(undefined)
</div>
`;
1 change: 1 addition & 0 deletions package/src/components/AddressCapture/v1/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./AddressCapture";
1 change: 1 addition & 0 deletions styleguide.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ module.exports = {
sections: [
generateSection({
componentNames: [
"AddressCapture",
"ShopLogo"
],
content: "styleguide/src/sections/General.md",
Expand Down

0 comments on commit da5eb69

Please sign in to comment.