├── .gitignore
├── README.md
├── checkout-form-rhf
├── .firebaserc
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── .storybook
│ ├── main.ts
│ └── preview.tsx
├── README.md
├── assets
│ └── screen-shot.png
├── firebase.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── locales
│ │ ├── en
│ │ │ └── translation.json
│ │ └── es
│ │ │ └── translation.json
│ └── manifest.json
├── src
│ ├── App.tsx
│ ├── components
│ │ ├── AddressForm
│ │ │ ├── AddressForm.tsx
│ │ │ └── index.ts
│ │ ├── AddressView
│ │ │ ├── AddressView.tsx
│ │ │ └── index.ts
│ │ ├── ContactInfoForm
│ │ │ ├── ContactInfoForm.tsx
│ │ │ └── index.ts
│ │ ├── Form
│ │ │ ├── Checkbox.tsx
│ │ │ ├── ErrorMessage.tsx
│ │ │ ├── LimitedTextField.tsx
│ │ │ ├── Radio.tsx
│ │ │ ├── TextField.tsx
│ │ │ └── index.ts
│ │ ├── Header
│ │ │ ├── Header.module.css
│ │ │ ├── Header.tsx
│ │ │ └── index.ts
│ │ ├── Loading
│ │ │ ├── Loading.tsx
│ │ │ └── index.ts
│ │ ├── OrderDetail
│ │ │ ├── OrderDetail.tsx
│ │ │ ├── ShippingMethodText.tsx
│ │ │ └── index.ts
│ │ ├── OrderSummary
│ │ │ ├── OrderSummary.tsx
│ │ │ └── index.ts
│ │ ├── PaymentForm
│ │ │ ├── BankAccountForm.tsx
│ │ │ ├── CreditCardForm.tsx
│ │ │ ├── PaymentForm.tsx
│ │ │ └── index.ts
│ │ ├── PaymentView
│ │ │ ├── PaymentTypeText.tsx
│ │ │ ├── PaymentView.tsx
│ │ │ └── index.ts
│ │ ├── ShippingOptionsForm
│ │ │ ├── ShippingOptionsForm.tsx
│ │ │ └── index.ts
│ │ └── index.ts
│ ├── contexts
│ │ ├── OrderContext.tsx
│ │ └── index.ts
│ ├── data
│ │ ├── address.ts
│ │ ├── index.ts
│ │ └── order.ts
│ ├── i18n.ts
│ ├── index.css
│ ├── index.tsx
│ ├── models
│ │ ├── Address.ts
│ │ ├── ContactInfo.ts
│ │ ├── Item.ts
│ │ ├── Order.ts
│ │ ├── OrderItem.ts
│ │ ├── PaymentMethod.ts
│ │ ├── ShippingOptions.ts
│ │ ├── ValidationError.ts
│ │ └── index.ts
│ ├── pages
│ │ ├── CheckoutPage
│ │ │ ├── CheckoutActions.tsx
│ │ │ ├── CheckoutForm.tsx
│ │ │ ├── CheckoutPage.tsx
│ │ │ └── index.ts
│ │ └── index.ts
│ ├── react-app-env.d.ts
│ ├── stories
│ │ ├── AddressForm.stories.tsx
│ │ ├── ContactInfoForm.stories.tsx
│ │ ├── LimitedTextField.stories.tsx
│ │ ├── PaymentForm.stories.tsx
│ │ ├── ShippingOptionsForm.stories.tsx
│ │ └── TextField.stories.tsx
│ └── utils
│ │ ├── index.ts
│ │ └── yupLocale.ts
├── tsconfig.json
└── yarn.lock
└── docs
├── asset-manifest.json
├── favicon.ico
├── iframe.html
├── index.html
├── locales
├── en
│ └── translation.json
└── es
│ └── translation.json
├── main.22514c02e870346d0f24.bundle.js
├── main.22514c02e870346d0f24.bundle.js.map
├── main.51a3345951494c002c77.bundle.js
├── manifest.json
├── runtime~main.22514c02e870346d0f24.bundle.js
├── runtime~main.22514c02e870346d0f24.bundle.js.map
├── runtime~main.6a9b04192e3176eff72a.bundle.js
├── static
├── css
│ ├── main.cf37a24c.chunk.css
│ ├── main.cf37a24c.chunk.css.map
│ ├── vendors~main.20aa2d7b.chunk.css
│ └── vendors~main.20aa2d7b.chunk.css.map
└── media
│ └── getFetch.d7d6010d.cjs
├── vendors~main.22514c02e870346d0f24.bundle.js
├── vendors~main.22514c02e870346d0f24.bundle.js.LICENSE.txt
├── vendors~main.22514c02e870346d0f24.bundle.js.map
├── vendors~main.33c5a3c5c6b3b33439d9.bundle.js
└── vendors~main.33c5a3c5c6b3b33439d9.bundle.js.LICENSE.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # Compiled output
4 | dist
5 |
6 | # Dependencies
7 | node_modules
8 |
9 | # IDEs and editors
10 | .idea
11 |
12 | # Misc
13 | coverage
14 | legacy.d.ts
15 | next.d.ts
16 | *.log
17 | *.orig
18 |
19 | # System Files
20 | .DS_Store
21 | .eslintcache
22 | Thumbs.db
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Form Examples
2 |
3 | Examples of forms created using popular libraries such as [Formik](https://formik.org/docs/overview)
4 | and [React Hook Form](https://react-hook-form.com/).
5 |
--------------------------------------------------------------------------------
/checkout-form-rhf/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "checkout-form-rhf"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/checkout-form-rhf/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # IDEs and editors
15 | /.idea
16 | /.vscode
17 |
18 | # misc
19 | .DS_Store
20 | .env.local
21 | .env.development.local
22 | .env.test.local
23 | .env.production.local
24 | .firebase
25 |
26 | npm-debug.log*
27 | yarn-debug.log*
28 | yarn-error.log*
29 |
--------------------------------------------------------------------------------
/checkout-form-rhf/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
2 | package-lock.json
3 |
--------------------------------------------------------------------------------
/checkout-form-rhf/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | tabWidth: 4,
3 | singleQuote: true,
4 | proseWrap: 'always'
5 | };
6 |
--------------------------------------------------------------------------------
/checkout-form-rhf/.storybook/main.ts:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "stories": [
3 | "../src/**/*.stories.mdx",
4 | "../src/**/*.stories.@(js|jsx|ts|tsx)"
5 | ],
6 | "addons": [
7 | "@storybook/addon-links",
8 | "@storybook/addon-essentials",
9 | "@storybook/preset-create-react-app"
10 | ]
11 | }
--------------------------------------------------------------------------------
/checkout-form-rhf/.storybook/preview.tsx:
--------------------------------------------------------------------------------
1 | import React, { Suspense } from 'react';
2 | import { addDecorator } from '@storybook/react';
3 | import * as yup from 'yup';
4 | import '../src/i18n';
5 | import { Loading } from '../src/components';
6 | import { yupLocale } from '../src/utils'
7 |
8 | import 'bootstrap/dist/css/bootstrap.min.css';
9 | import '../src/index.css';
10 |
11 | yup.setLocale(yupLocale)
12 |
13 | export const parameters = {
14 | actions: { argTypesRegex: '^on[A-Z].*' },
15 | };
16 |
17 | const StoryDecorator = (Story: any) => (
18 | }>
19 |
20 |
21 | );
22 |
23 | addDecorator(StoryDecorator);
24 |
--------------------------------------------------------------------------------
/checkout-form-rhf/README.md:
--------------------------------------------------------------------------------
1 | # Checkout Form | React Hook Form
2 |
3 | This example illustrates best practices in creating large complex forms using
4 | [React Hook Form](https://react-hook-form.com/). The use case is a checkout form
5 | for an online order. It represents a good mix of challenges that you may
6 | encounter when creating your own large complex form. For example,
7 |
8 | 1. How to break a large monolithic form into smaller "sub-forms" that you can
9 | test independently?
10 | 2. How to create reusable sub-forms that can be composed in different ways to
11 | target multiple use cases?
12 | 3. How to do conditional validation, e.g. changing validations dynamically based
13 | on the payment method?
14 | 4. How to break large validation schemas into smaller composable schemas?
15 | 5. How to incorporate i18n into your form?
16 |
17 | 
18 |
19 | ## Live Demo
20 |
21 | Try out a live demo [here](https://checkout-form-rhf.web.app/).
22 |
23 | ## Getting Started
24 |
25 | Execute the following commands to build and run the example.
26 |
27 | ```bash
28 | $ yarn
29 | $ yarn start
30 | ```
31 |
32 | Now point your browser to http://localhost:3000/.
33 |
34 | ## Running Storybook
35 |
36 | To understand the behavior of individual components and sub-forms, run them
37 | independently in Storybook:
38 |
39 | ```bash
40 | $ yarn storybook
41 | ```
42 |
--------------------------------------------------------------------------------
/checkout-form-rhf/assets/screen-shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nareshbhatia/form-examples/17f3ef2c9908ccbe620804831addb63e39155389/checkout-form-rhf/assets/screen-shot.png
--------------------------------------------------------------------------------
/checkout-form-rhf/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "build",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ],
9 | "rewrites": [
10 | {
11 | "source": "**",
12 | "destination": "/index.html"
13 | }
14 | ]
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/checkout-form-rhf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "checkout-form-rhf",
3 | "description": "Checkout form using React Hook Form",
4 | "version": "0.1.0",
5 | "author": "Naresh Bhatia",
6 | "license": "MIT",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/nareshbhatia/form-examples.git",
10 | "directory": "checkout-form-rhf"
11 | },
12 | "scripts": {
13 | "analyze": "source-map-explorer 'build/static/js/*.js'",
14 | "build": "react-scripts build",
15 | "eject": "react-scripts eject",
16 | "format": "prettier --write README.md 'src/**/{*.md,*.json,*.ts*}'",
17 | "start": "react-scripts start",
18 | "test": "react-scripts test",
19 | "test:coverage": "react-scripts test --coverage --watchAll=false",
20 | "storybook": "start-storybook -p 6006 -s public",
21 | "build-storybook": "build-storybook -s public -o ../docs"
22 | },
23 | "dependencies": {
24 | "@hookform/resolvers": "^1.2.0",
25 | "@react-force/number-utils": "^2.1.0",
26 | "@react-force/utils": "^2.3.0",
27 | "bootstrap": "^4.5.3",
28 | "i18next": "^19.8.4",
29 | "i18next-http-backend": "^1.0.21",
30 | "react": "^17.0.1",
31 | "react-dom": "^17.0.1",
32 | "react-hook-form": "^6.13.1",
33 | "react-i18next": "^11.8.4",
34 | "yup": "^0.32.8"
35 | },
36 | "devDependencies": {
37 | "@babel/core": "^7.12.10",
38 | "@storybook/addon-actions": "^6.1.11",
39 | "@storybook/addon-essentials": "^6.1.11",
40 | "@storybook/addon-links": "^6.1.11",
41 | "@storybook/node-logger": "^6.1.11",
42 | "@storybook/preset-create-react-app": "^3.1.5",
43 | "@storybook/react": "^6.1.11",
44 | "@testing-library/jest-dom": "^5.11.6",
45 | "@testing-library/react": "^11.2.2",
46 | "@testing-library/user-event": "^12.6.0",
47 | "@types/jest": "26.0.19",
48 | "@types/node": "14.14.16",
49 | "@types/react": "17.0.0",
50 | "@types/react-dom": "17.0.0",
51 | "@types/yup": "^0.29.11",
52 | "babel-loader": "8.1.0",
53 | "husky": "^4.3.6",
54 | "prettier": "^2.2.1",
55 | "pretty-quick": "^3.1.0",
56 | "react-is": "^17.0.1",
57 | "react-scripts": "4.0.1",
58 | "source-map-explorer": "^2.5.1",
59 | "typescript": "4.1.3"
60 | },
61 | "eslintConfig": {
62 | "extends": "react-app"
63 | },
64 | "husky": {
65 | "hooks": {
66 | "pre-commit": "pretty-quick --staged"
67 | }
68 | },
69 | "browserslist": {
70 | "production": [
71 | ">0.2%",
72 | "not dead",
73 | "not op_mini all"
74 | ],
75 | "development": [
76 | "last 1 chrome version",
77 | "last 1 firefox version",
78 | "last 1 safari version"
79 | ]
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/checkout-form-rhf/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nareshbhatia/form-examples/17f3ef2c9908ccbe620804831addb63e39155389/checkout-form-rhf/public/favicon.ico
--------------------------------------------------------------------------------
/checkout-form-rhf/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
23 |
24 | Checkout Form
25 |
26 |
29 |
33 |
37 |
38 |
39 |
40 |
41 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/checkout-form-rhf/public/locales/en/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "text": {
3 | "accountHolderName": "Account holder's name",
4 | "accountNumber": "Account number",
5 | "address": "Address",
6 | "bankAccount": "Bank Account",
7 | "bankName": "Bank name",
8 | "billingAddress": "Billing Address",
9 | "cardNumber": "Card number",
10 | "characters": "characters",
11 | "checkout": "Checkout",
12 | "city": "City",
13 | "companyOptional": "Company (optional)",
14 | "contactInfo": "Contact Information",
15 | "creditCard": "Credit Card",
16 | "creditCardNumber": "Credit card number",
17 | "cvv": "CVV",
18 | "email": "Email",
19 | "expiration": "Expiration",
20 | "firstName": "First name",
21 | "giftWrapping": "Gift wrapping",
22 | "ground": "Ground",
23 | "groundLong": "Ground (3-5 days)",
24 | "items": "Items",
25 | "lastName": "Last name",
26 | "nameOnCard": "Name on card",
27 | "no": "No",
28 | "overnight": "Overnight",
29 | "orderDetail": "Order Detail",
30 | "orderTotal": "Order total",
31 | "orderSummary": "Order Summary",
32 | "paymentMethod": "Payment Method",
33 | "placeYourOrder": "Place your order",
34 | "quantity": "Quantity",
35 | "routingNumber": "Routing number",
36 | "secondDay": "Second Day",
37 | "shippingAddress": "Shipping Address",
38 | "shippingHandling": "Shipping & handling",
39 | "shippingMethod": "Shipping method",
40 | "shippingOptions": "Shipping Options",
41 | "state": "State",
42 | "yes": "Yes",
43 | "zip": "Zip"
44 | },
45 | "validations": {
46 | "email": "Email is invalid",
47 | "invalid": "Field is invalid",
48 | "invalidType": "Must be a {{type}}",
49 | "required": "Field is required",
50 | "stringMin": "Must be at least {{min}} characters",
51 | "stringMax": "Must be at most {{max}} characters"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/checkout-form-rhf/public/locales/es/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "text": {
3 | "accountHolderName": "Nombre del titular de la cuenta",
4 | "accountNumber": "Número de cuenta",
5 | "address": "Dirección",
6 | "bankAccount": "Cuenta Bancaria",
7 | "bankName": "Nombre del banco",
8 | "billingAddress": "Dirección de Facturación",
9 | "cardNumber": "Número de tarjeta",
10 | "characters": "caracteres",
11 | "checkout": "Revisa",
12 | "city": "Ciudad",
13 | "companyOptional": "Companía (opcional)",
14 | "contactInfo": "Información del Contacto",
15 | "creditCard": "Tarjeta de Crédito",
16 | "creditCardNumber": "Número de tarjeta de crédito",
17 | "cvv": "CVV",
18 | "email": "Email",
19 | "expiration": "Vencimiento",
20 | "firstName": "Primer nombre",
21 | "giftWrapping": "Envoltorio de Regalo",
22 | "ground": "Suelo",
23 | "groundLong": "Suelo (3-5 días)",
24 | "items": "Artículos",
25 | "lastName": "Apellido",
26 | "nameOnCard": "Nombre en la tarjeta",
27 | "no": "No",
28 | "orderDetail": "Detalle de la orden",
29 | "orderTotal": "Total del pedido",
30 | "orderSummary": "Resumen del pedido",
31 | "overnight": "Durante la noche",
32 | "paymentMethod": "Método de Pago",
33 | "placeYourOrder": "Haga su pedido",
34 | "quantity": "Cantidad",
35 | "routingNumber": "Número de ruta",
36 | "secondDay": "Segundo Día",
37 | "shippingAddress": "Dirección de Envío",
38 | "shippingHandling": "Envío y manejo",
39 | "shippingMethod": "Método de envío",
40 | "shippingOptions": "Opciones de Envío",
41 | "state": "Estado",
42 | "yes": "Si",
43 | "zip": "Código Postal"
44 | },
45 | "validations": {
46 | "email": "El correo electrónico es invalido",
47 | "invalid": "El campo no es válido",
48 | "invalidType": "Tiene que ser un {{type}}",
49 | "required": "Se requiere campo",
50 | "stringMin": "Debe tener al menos {{min}} caracteres",
51 | "stringMax": "Debe tener como máximo {{max}} caracteres"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/checkout-form-rhf/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Checkout Form",
3 | "name": "Checkout Form",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React, { Suspense } from 'react';
2 | import { Header, Loading } from './components';
3 | import { OrderContextProvider } from './contexts';
4 | import { CheckoutPage } from './pages';
5 |
6 | export const App = () => {
7 | return (
8 | }>
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/AddressForm/AddressForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { useFormContext } from 'react-hook-form';
3 | import { useTranslation } from 'react-i18next';
4 | import * as yup from 'yup';
5 | import { TextField } from '../Form';
6 |
7 | export const getAddressSchema = () =>
8 | yup.object().shape({
9 | firstName: yup.string().required().min(2),
10 | lastName: yup.string().required().min(2),
11 | company: yup.string(),
12 | address: yup.string().required(),
13 | city: yup.string().required(),
14 | state: yup.string().required(),
15 | zip: yup.string().required(),
16 | });
17 |
18 | export interface AddressFormProps {
19 | title?: string;
20 |
21 | /** parent name e.g. "shippingAddress" */
22 | parentName: string;
23 | }
24 |
25 | export const AddressForm = ({ title, parentName }: AddressFormProps) => {
26 | const { t } = useTranslation();
27 | const { errors, register } = useFormContext();
28 |
29 | return (
30 |
31 | {title !== undefined ? {title}
: null}
32 |
33 |
34 |
41 |
42 |
43 |
50 |
51 |
52 |
53 |
54 |
61 |
62 |
63 |
64 |
71 |
72 |
73 |
74 |
75 |
82 |
83 |
84 |
91 |
92 |
93 |
100 |
101 |
102 |
103 | );
104 | };
105 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/AddressForm/index.ts:
--------------------------------------------------------------------------------
1 | export * from './AddressForm';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/AddressView/AddressView.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { StringUtils } from '@react-force/utils';
3 | import { Address } from '../../models';
4 |
5 | const { isBlank } = StringUtils;
6 |
7 | export interface AddressViewProps {
8 | label?: string;
9 | address: Address;
10 | }
11 |
12 | export const AddressView = ({ label, address }: AddressViewProps) => {
13 | const {
14 | firstName,
15 | lastName,
16 | company,
17 | address: addressLine,
18 | city,
19 | state,
20 | zip,
21 | } = address;
22 | return (
23 |
24 | {label !== undefined ? {label}
: null}
25 |
26 | {firstName} {lastName}
27 | {!isBlank(company) ? (
28 |
29 |
30 | {company}
31 |
32 | ) : null}
33 |
34 | {addressLine}
35 |
36 | {city}, {state} {zip}
37 |
38 |
39 | );
40 | };
41 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/AddressView/index.ts:
--------------------------------------------------------------------------------
1 | export * from './AddressView';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/ContactInfoForm/ContactInfoForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { useFormContext } from 'react-hook-form';
3 | import { useTranslation } from 'react-i18next';
4 | import * as yup from 'yup';
5 | import { TextField } from '../Form';
6 |
7 | export const getContactInfoSchema = () =>
8 | yup.object().shape({
9 | email: yup.string().email().required(),
10 | });
11 |
12 | export const ContactInfoForm = () => {
13 | const { t } = useTranslation();
14 | const { errors, register } = useFormContext();
15 |
16 | return (
17 |
18 | {t('text.contactInfo')}
19 |
20 |
27 |
28 |
29 | );
30 | };
31 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/ContactInfoForm/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ContactInfoForm';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Form/Checkbox.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ValidationError } from '../../models';
3 | import { ErrorMessage } from './ErrorMessage';
4 |
5 | interface InputInjectedProps {
6 | id?: string;
7 | name?: string;
8 | type?: string;
9 | ref?: React.Ref;
10 | className: string;
11 | onBlur?: (e: React.FocusEvent) => void;
12 | onChange?: (e: React.ChangeEvent) => void;
13 | }
14 |
15 | export interface CheckboxProps {
16 | /** used to make label and errorText accessible for screen readers */
17 | id?: string;
18 |
19 | /** passed directly to the input element */
20 | name?: string;
21 |
22 | /** the label content */
23 | label?: React.ReactNode;
24 |
25 | /** passed directly to the input element */
26 | ref?: React.Ref;
27 |
28 | /** error text */
29 | error?: ValidationError | string;
30 |
31 | renderContainer?: (props: InputInjectedProps) => JSX.Element;
32 |
33 | onBlur?: (e: React.FocusEvent) => void;
34 | onChange?: (e: React.ChangeEvent) => void;
35 | }
36 |
37 | /**
38 | * Uses the "Render Prop" pattern to pass through arbitrary props that it
39 | * doesn't understand.
40 | * See https://blog.andrewbran.ch/polymorphic-react-components/
41 | */
42 | export const Checkbox = React.forwardRef(
43 | (
44 | {
45 | id,
46 | name,
47 | label,
48 | error,
49 | renderContainer = (props) => ,
50 | onBlur,
51 | onChange,
52 | }: CheckboxProps,
53 | ref
54 | ) => {
55 | return (
56 |
57 | {renderContainer({
58 | id,
59 | name,
60 | type: 'checkbox',
61 | ref,
62 | className: 'form-check-input',
63 | onBlur,
64 | onChange,
65 | })}
66 | {label !== undefined ? (
67 |
70 | ) : null}
71 |
72 |
73 | );
74 | }
75 | );
76 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Form/ErrorMessage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { ValidationError } from '../../models';
4 |
5 | export interface ErrorMessageProps {
6 | error?: ValidationError | string;
7 | }
8 |
9 | export const ErrorMessage = ({ error }: ErrorMessageProps) => {
10 | const { t } = useTranslation();
11 |
12 | if (error === undefined) {
13 | return null;
14 | } else if (typeof error === 'string') {
15 | return {error}
;
16 | } else {
17 | const { key, values } = error;
18 | return {t(key, values)}
;
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Form/LimitedTextField.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState } from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { ValidationError } from '../../models';
4 | import { ErrorMessage } from './ErrorMessage';
5 |
6 | interface InputInjectedProps {
7 | id?: string;
8 | name?: string;
9 | type?: string;
10 | ref?: React.Ref;
11 | className: string;
12 | onBlur?: (e: React.FocusEvent) => void;
13 | onChange?: (e: React.ChangeEvent) => void;
14 | }
15 |
16 | export interface LimitedTextFieldProps {
17 | /** used to make label and errorText accessible for screen readers */
18 | id?: string;
19 |
20 | /** passed directly to the input element */
21 | name?: string;
22 |
23 | /** the label content */
24 | label?: React.ReactNode;
25 |
26 | /** maximum count of characters allowed in text field */
27 | maxCount: number;
28 |
29 | /** passed directly to the input element */
30 | ref?: React.Ref;
31 |
32 | /** error text */
33 | error?: ValidationError | string;
34 |
35 | renderContainer?: (props: InputInjectedProps) => JSX.Element;
36 |
37 | onBlur?: (e: React.FocusEvent) => void;
38 | onChange?: (e: React.ChangeEvent) => void;
39 | }
40 |
41 | /**
42 | * Uses the "Render Prop" pattern to pass through arbitrary props that it
43 | * doesn't understand.
44 | * See https://blog.andrewbran.ch/polymorphic-react-components/
45 | */
46 | export const LimitedTextField = React.forwardRef(
47 | (
48 | {
49 | id,
50 | name,
51 | label,
52 | maxCount,
53 | error,
54 | renderContainer = (props) => ,
55 | onBlur,
56 | onChange,
57 | }: LimitedTextFieldProps,
58 | ref
59 | ) => {
60 | const { t } = useTranslation();
61 | const [value, setValue] = useState('');
62 | const remainingCount = maxCount - value.length;
63 |
64 | const handleChange = (e: React.ChangeEvent) => {
65 | setValue(e.currentTarget.value);
66 | if (onChange !== undefined) onChange(e);
67 | };
68 |
69 | return (
70 |
71 | {label !== undefined ? (
72 |
73 | ) : null}
74 | {renderContainer({
75 | id,
76 | name,
77 | type: 'text',
78 | ref,
79 | className: 'form-control form-control-sm',
80 | onBlur,
81 | onChange: handleChange,
82 | })}
83 |
84 | {remainingCount} {t('text.characters')}
85 |
86 |
87 |
88 | );
89 | }
90 | );
91 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Form/Radio.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { ValidationError } from '../../models';
3 | import { ErrorMessage } from './ErrorMessage';
4 |
5 | interface InputInjectedProps {
6 | id?: string;
7 | value?: string;
8 | name?: string;
9 | type?: string;
10 | ref?: React.Ref;
11 | className: string;
12 | onBlur?: (e: React.FocusEvent) => void;
13 | onChange?: (e: React.ChangeEvent) => void;
14 | }
15 |
16 | export interface RadioProps {
17 | /** used to make label and errorText accessible for screen readers */
18 | id?: string;
19 |
20 | /** used to make label and errorText accessible for screen readers */
21 | value?: string;
22 |
23 | /** passed directly to the input element */
24 | name?: string;
25 |
26 | /** the label content */
27 | label?: React.ReactNode;
28 |
29 | /** passed directly to the input element */
30 | ref?: React.Ref;
31 |
32 | /** error text */
33 | error?: ValidationError | string;
34 |
35 | renderContainer?: (props: InputInjectedProps) => JSX.Element;
36 |
37 | onBlur?: (e: React.FocusEvent) => void;
38 | onChange?: (e: React.ChangeEvent) => void;
39 | }
40 |
41 | /**
42 | * Uses the "Render Prop" pattern to pass through arbitrary props that it
43 | * doesn't understand.
44 | * See https://blog.andrewbran.ch/polymorphic-react-components/
45 | */
46 | export const Radio = React.forwardRef(
47 | (
48 | {
49 | id,
50 | value,
51 | name,
52 | label,
53 | error,
54 | renderContainer = (props) => ,
55 | onBlur,
56 | onChange,
57 | }: RadioProps,
58 | ref
59 | ) => {
60 | return (
61 |
62 | {renderContainer({
63 | id,
64 | value,
65 | name,
66 | type: 'radio',
67 | ref,
68 | className: 'form-check-input',
69 | onBlur,
70 | onChange,
71 | })}
72 | {label !== undefined ? (
73 |
76 | ) : null}
77 |
78 |
79 | );
80 | }
81 | );
82 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Form/TextField.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { ValidationError } from '../../models';
3 | import { ErrorMessage } from './ErrorMessage';
4 |
5 | interface InputInjectedProps {
6 | id?: string;
7 | name?: string;
8 | type?: string;
9 | ref?: React.Ref;
10 | className: string;
11 | onBlur?: (e: React.FocusEvent) => void;
12 | onChange?: (e: React.ChangeEvent) => void;
13 | }
14 |
15 | export interface TextFieldProps {
16 | /** used to make label and errorText accessible for screen readers */
17 | id?: string;
18 |
19 | /** passed directly to the input element */
20 | name?: string;
21 |
22 | /** the label content */
23 | label?: React.ReactNode;
24 |
25 | /** passed directly to the input element */
26 | ref?: React.Ref;
27 |
28 | /** error text */
29 | error?: ValidationError | string;
30 |
31 | renderContainer?: (props: InputInjectedProps) => JSX.Element;
32 |
33 | onBlur?: (e: React.FocusEvent) => void;
34 | onChange?: (e: React.ChangeEvent) => void;
35 | }
36 |
37 | /**
38 | * Uses the "Render Prop" pattern to pass through arbitrary props that it
39 | * doesn't understand.
40 | * See https://blog.andrewbran.ch/polymorphic-react-components/
41 | */
42 | export const TextField = React.forwardRef(
43 | (
44 | {
45 | id,
46 | name,
47 | label,
48 | error,
49 | renderContainer = (props) => ,
50 | onBlur,
51 | onChange,
52 | }: TextFieldProps,
53 | ref
54 | ) => {
55 | return (
56 |
57 | {label !== undefined ? (
58 |
59 | ) : null}
60 | {renderContainer({
61 | id,
62 | name,
63 | type: 'text',
64 | ref,
65 | className: 'form-control form-control-sm',
66 | onBlur,
67 | onChange,
68 | })}
69 |
70 |
71 | );
72 | }
73 | );
74 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Form/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Checkbox';
2 | export * from './LimitedTextField';
3 | export * from './Radio';
4 | export * from './TextField';
5 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Header/Header.module.css:
--------------------------------------------------------------------------------
1 | .langSelect {
2 | width: 160px !important;
3 | }
4 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Header/Header.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import styles from './Header.module.css';
4 |
5 | export const Header = () => {
6 | const { t, i18n } = useTranslation();
7 |
8 | const handleLanguageChange = (e: React.ChangeEvent) => {
9 | i18n.changeLanguage(e.target.value);
10 | };
11 |
12 | return (
13 |
25 | );
26 | };
27 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Header/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Header';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Loading/Loading.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export const Loading = () => {
4 | return (
5 |
6 |
7 | Loading...
8 |
9 |
10 | );
11 | };
12 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/Loading/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Loading';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/OrderDetail/OrderDetail.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { StringUtils } from '@react-force/utils';
3 | import { useTranslation } from 'react-i18next';
4 | import { Order } from '../../models';
5 | import { AddressView } from '../AddressView';
6 | import { PaymentView } from '../PaymentView';
7 | import { ShippingMethodText } from './ShippingMethodText';
8 |
9 | const { isBlank } = StringUtils;
10 |
11 | export interface OrderDetailProps {
12 | order: Order;
13 | }
14 |
15 | export const OrderDetail = ({ order }: OrderDetailProps) => {
16 | const { t } = useTranslation();
17 | const {
18 | contactInfo,
19 | shippingAddress,
20 | shippingOptions,
21 | paymentMethod,
22 | } = order;
23 |
24 | return (
25 |
26 | {t('text.orderDetail')}
27 |
28 |
{t('text.contactInfo')}
29 |
Email: {contactInfo.email}
30 |
31 | {!isBlank(shippingAddress.firstName) ? (
32 |
36 | ) : null}
37 |
38 |
{t('text.shippingOptions')}
39 |
40 | {t('text.shippingMethod')}:{' '}
41 |
44 |
45 | {t('text.giftWrapping')}:{' '}
46 | {shippingOptions.giftWrapping
47 | ? t('text.yes')
48 | : t('text.no')}
49 |
50 |
51 |
52 |
53 |
54 | );
55 | };
56 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/OrderDetail/ShippingMethodText.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { ShippingMethod } from '../../models';
4 |
5 | export interface ShippingMethodTextProps {
6 | shippingMethod: ShippingMethod;
7 | }
8 |
9 | export const ShippingMethodText = ({
10 | shippingMethod,
11 | }: ShippingMethodTextProps) => {
12 | const { t } = useTranslation();
13 |
14 | const ShippingMethodNames: { [key in ShippingMethod]: string } = {
15 | ground: t('text.ground'),
16 | secondDay: t('text.secondDay'),
17 | overnight: t('text.overnight'),
18 | };
19 |
20 | return {ShippingMethodNames[shippingMethod]};
21 | };
22 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/OrderDetail/index.ts:
--------------------------------------------------------------------------------
1 | export * from './OrderDetail';
2 | export * from './ShippingMethodText';
3 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/OrderSummary/OrderSummary.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { NumberUtils } from '@react-force/number-utils';
3 | import { useTranslation } from 'react-i18next';
4 | import { Order, OrderItem } from '../../models';
5 |
6 | export interface OrderSummaryProps {
7 | order: Order;
8 | }
9 |
10 | export const OrderSummary = ({ order }: OrderSummaryProps) => {
11 | const { t } = useTranslation();
12 | const { orderItems } = order;
13 | const {
14 | orderItemsTotal,
15 | shippingCharges,
16 | orderTotal,
17 | } = Order.getOrderTotal(order);
18 | const orderItemsTotalStr = NumberUtils.formatAsMoney(orderItemsTotal);
19 | const shippingChargesStr = NumberUtils.formatAsMoney(shippingCharges);
20 | const orderTotalStr = NumberUtils.formatAsMoney(orderTotal);
21 |
22 | return (
23 |
24 |
25 | {t('text.orderSummary')}
26 |
27 | {orderItems.length}
28 |
29 |
30 |
31 | {orderItems.map((orderItem) => (
32 | -
36 |
37 |
{orderItem.item.name}
38 |
39 | {t('text.quantity')}: {orderItem.qty}
40 |
41 |
42 |
43 | $
44 | {NumberUtils.formatAsMoney(
45 | OrderItem.getTotal(orderItem)
46 | )}
47 |
48 |
49 | ))}
50 | -
51 |
52 | {t('text.items')}
53 | ${orderItemsTotalStr}
54 |
55 |
56 | {t('text.shippingHandling')}
57 | ${shippingChargesStr}
58 |
59 |
60 | -
61 | {t('text.orderTotal')}
62 | ${orderTotalStr}
63 |
64 |
65 |
66 | );
67 | };
68 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/OrderSummary/index.ts:
--------------------------------------------------------------------------------
1 | export * from './OrderSummary';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/PaymentForm/BankAccountForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { useFormContext } from 'react-hook-form';
3 | import { useTranslation } from 'react-i18next';
4 | import * as yup from 'yup';
5 | import { TextField } from '../Form';
6 |
7 | export const getBankAccountSchema = () =>
8 | yup.object().shape({
9 | accountHolderName: yup.string().required(),
10 | bankName: yup.string().required(),
11 | routingNumber: yup.string().required(),
12 | accountNumber: yup.string().required(),
13 | });
14 |
15 | export const BankAccountForm = () => {
16 | const { t } = useTranslation();
17 | const { errors, register } = useFormContext();
18 |
19 | return (
20 |
21 |
22 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
42 |
43 |
50 |
51 |
52 |
53 |
60 |
61 |
62 |
63 | );
64 | };
65 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/PaymentForm/CreditCardForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { useFormContext } from 'react-hook-form';
3 | import { useTranslation } from 'react-i18next';
4 | import * as yup from 'yup';
5 | import { TextField } from '../Form';
6 |
7 | export const getCreditCardSchema = () =>
8 | yup.object().shape({
9 | nameOnCard: yup.string().required(),
10 | cardNumber: yup.string().required(),
11 | expiration: yup.string().required(),
12 | cvv: yup.number().required(),
13 | });
14 |
15 | export const CreditCardForm = () => {
16 | const { t } = useTranslation();
17 | const { errors, register } = useFormContext();
18 |
19 | return (
20 |
21 |
22 |
23 |
30 |
31 |
32 |
39 |
40 |
41 |
42 |
43 |
50 |
51 |
52 |
59 |
60 |
61 |
62 | );
63 | };
64 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/PaymentForm/PaymentForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { useFormContext } from 'react-hook-form';
3 | import { useTranslation } from 'react-i18next';
4 | import * as yup from 'yup';
5 | import { PaymentMethod } from '../../models';
6 | import { Radio } from '../Form';
7 | import { BankAccountForm, getBankAccountSchema } from './BankAccountForm';
8 | import { CreditCardForm, getCreditCardSchema } from './CreditCardForm';
9 |
10 | export const getPaymentSchema = () =>
11 | yup.lazy((value) => {
12 | if (value === undefined) {
13 | return yup.mixed().notRequired();
14 | }
15 | const paymentMethod = value as PaymentMethod;
16 | return paymentMethod.type === 'creditCard'
17 | ? getCreditCardSchema()
18 | : getBankAccountSchema();
19 | });
20 |
21 | export const PaymentForm = () => {
22 | const { t } = useTranslation();
23 | const { errors, register, watch } = useFormContext();
24 |
25 | const paymentType = watch('paymentMethod.type');
26 |
27 | return (
28 |
29 | {t('text.paymentMethod')}
30 |
38 |
46 | {paymentType === 'creditCard' ? (
47 |
48 | ) : (
49 |
50 | )}
51 |
52 | );
53 | };
54 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/PaymentForm/index.ts:
--------------------------------------------------------------------------------
1 | export * from './PaymentForm';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/PaymentView/PaymentTypeText.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { useTranslation } from 'react-i18next';
3 | import { PaymentType } from '../../models';
4 |
5 | export interface PaymentTypeTextProps {
6 | paymentType: PaymentType;
7 | }
8 |
9 | export const PaymentTypeText = ({ paymentType }: PaymentTypeTextProps) => {
10 | const { t } = useTranslation();
11 |
12 | const PaymentTypeNames: { [key in PaymentType]: string } = {
13 | creditCard: t('text.creditCard'),
14 | bankAccount: t('text.bankAccount'),
15 | };
16 |
17 | return {PaymentTypeNames[paymentType]};
18 | };
19 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/PaymentView/PaymentView.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { StringUtils } from '@react-force/utils';
3 | import { useTranslation } from 'react-i18next';
4 | import { PaymentMethod } from '../../models';
5 | import { PaymentTypeText } from './PaymentTypeText';
6 |
7 | const { isBlank } = StringUtils;
8 |
9 | export interface PaymentViewProps {
10 | paymentMethod: PaymentMethod;
11 | }
12 |
13 | export const PaymentView = ({ paymentMethod }: PaymentViewProps) => {
14 | const { t } = useTranslation();
15 |
16 | return (
17 |
18 | {t('text.paymentMethod')}
19 |
20 |
21 |
22 | {paymentMethod.type === 'creditCard' &&
23 | !isBlank(paymentMethod.nameOnCard) ? (
24 |
25 | {paymentMethod.nameOnCard}
26 |
27 | {t('text.cardNumber')}: {paymentMethod.cardNumber}
28 |
29 | {t('text.expiration')}: {paymentMethod.expiration}
30 |
31 | {t('text.cvv')}: {paymentMethod.cvv}
32 |
33 | ) : null}
34 | {paymentMethod.type === 'bankAccount' &&
35 | !isBlank(paymentMethod.accountHolderName) ? (
36 |
37 | {paymentMethod.accountHolderName}
38 |
39 | {paymentMethod.bankName}
40 |
41 | {t('text.routingNumber')}: {paymentMethod.routingNumber}
42 |
43 | {t('text.accountNumber')}: {paymentMethod.accountNumber}
44 |
45 | ) : null}
46 |
47 |
48 | );
49 | };
50 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/PaymentView/index.ts:
--------------------------------------------------------------------------------
1 | export * from './PaymentTypeText';
2 | export * from './PaymentView';
3 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/ShippingOptionsForm/ShippingOptionsForm.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 | import { useFormContext } from 'react-hook-form';
3 | import { useTranslation } from 'react-i18next';
4 | import * as yup from 'yup';
5 | import { ShippingMethod } from '../../models';
6 | import { Checkbox, Radio } from '../Form';
7 |
8 | export const shippingOptionsSchema = yup.object().shape({
9 | shippingMethod: yup.string().required(),
10 | giftWrapping: yup.boolean().required(),
11 | });
12 |
13 | export interface ShippingOptionsFormProps {
14 | onShippingMethodChanged: (shippingMethod: ShippingMethod) => void;
15 | }
16 |
17 | export const ShippingOptionsForm = ({
18 | onShippingMethodChanged,
19 | }: ShippingOptionsFormProps) => {
20 | const { t } = useTranslation();
21 | const { errors, register } = useFormContext();
22 |
23 | const handleShippingMethodChanged = (
24 | event: React.ChangeEvent
25 | ) => {
26 | onShippingMethodChanged(event.target.value as ShippingMethod);
27 | };
28 |
29 | return (
30 |
31 | {t('text.shippingOptions')}
32 |
33 |
42 |
51 |
60 |
61 |
68 |
69 | );
70 | };
71 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/ShippingOptionsForm/index.ts:
--------------------------------------------------------------------------------
1 | export * from './ShippingOptionsForm';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from './AddressForm';
2 | export * from './AddressView';
3 | export * from './ContactInfoForm';
4 | export * from './Form';
5 | export * from './Header';
6 | export * from './Loading';
7 | export * from './OrderDetail';
8 | export * from './OrderSummary';
9 | export * from './PaymentForm';
10 | export * from './PaymentView';
11 | export * from './ShippingOptionsForm';
12 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/contexts/OrderContext.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from 'react';
2 | import { order as initialOrder } from '../data';
3 | import { Order } from '../models';
4 |
5 | // ---------- OrderContext ----------
6 | type OrderSetter = (order: Order) => void;
7 |
8 | const OrderContext = React.createContext(undefined);
9 | const OrderSetterContext = React.createContext(
10 | undefined
11 | );
12 |
13 | // ---------- Hooks ----------
14 | function useOrder(): Order {
15 | const order = useContext(OrderContext);
16 | if (order === undefined) {
17 | /* istanbul ignore next */
18 | throw new Error('useOrder must be used within a OrderContextProvider');
19 | }
20 | return order;
21 | }
22 |
23 | function useOrderSetter(): OrderSetter {
24 | const setOrder = useContext(OrderSetterContext);
25 | if (setOrder === undefined) {
26 | /* istanbul ignore next */
27 | throw new Error(
28 | 'useOrderSetter must be used within a OrderContextProvider'
29 | );
30 | }
31 | return setOrder;
32 | }
33 |
34 | // ---------- OrderContextProvider ----------
35 | const OrderContextProvider: React.FC = ({ children }) => {
36 | const [order, setOrder] = useState(initialOrder);
37 |
38 | return (
39 |
40 |
41 | {children}
42 |
43 |
44 | );
45 | };
46 |
47 | export { OrderContextProvider, useOrder, useOrderSetter };
48 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/contexts/index.ts:
--------------------------------------------------------------------------------
1 | export * from './OrderContext';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/data/address.ts:
--------------------------------------------------------------------------------
1 | import { Address } from '../models';
2 |
3 | export const address: Address = {
4 | firstName: 'Elon',
5 | lastName: 'Musk',
6 | company: 'Tesla, Inc.',
7 | address: ' 3500 Deer Creek Road',
8 | city: 'Palo Alto',
9 | state: 'CA',
10 | zip: '94304',
11 | };
12 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/data/index.ts:
--------------------------------------------------------------------------------
1 | export * from './address';
2 | export * from './order';
3 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/data/order.ts:
--------------------------------------------------------------------------------
1 | import { Order } from '../models';
2 |
3 | export const order: Order = {
4 | orderItems: [
5 | {
6 | item: {
7 | id: 'E01',
8 | name: 'Apple MacBook Pro',
9 | price: 699.0,
10 | },
11 | qty: 1,
12 | },
13 | {
14 | item: {
15 | id: 'E08',
16 | name: 'Nest Learning Thermostat',
17 | price: 249.0,
18 | },
19 | qty: 1,
20 | },
21 | {
22 | item: {
23 | id: 'M08',
24 | name: 'Pharrell Williams - Happy',
25 | price: 12.0,
26 | },
27 | qty: 1,
28 | },
29 | ],
30 | contactInfo: {
31 | email: 'emusk@teslamotors.com',
32 | },
33 | shippingAddress: {
34 | firstName: 'Elon',
35 | lastName: 'Musk',
36 | company: 'Tesla, Inc.',
37 | address: ' 3500 Deer Creek Road',
38 | city: 'Palo Alto',
39 | state: 'CA',
40 | zip: '94304',
41 | },
42 | shippingOptions: {
43 | shippingMethod: 'ground',
44 | giftWrapping: false,
45 | },
46 | paymentMethod: {
47 | type: 'creditCard',
48 | nameOnCard: '',
49 | cardNumber: '',
50 | expiration: '',
51 | cvv: 0,
52 | },
53 | };
54 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import i18n from 'i18next';
2 | import { initReactI18next } from 'react-i18next';
3 |
4 | import Backend from 'i18next-http-backend';
5 |
6 | i18n.use(Backend)
7 | .use(initReactI18next)
8 | .init({
9 | lng: 'en',
10 | debug: true,
11 |
12 | interpolation: {
13 | // not needed for react as it escapes by default
14 | escapeValue: false,
15 | },
16 | });
17 |
18 | export default i18n;
19 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | /* add top padding to make room for the header */
3 | padding-top: 4.5rem;
4 | }
5 |
6 | .container {
7 | max-width: 960px;
8 | }
9 |
10 | .error-text {
11 | width: 100%;
12 | margin-top: 0.25rem;
13 | font-size: 80%;
14 | color: var(--danger);
15 | }
16 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import * as yup from 'yup';
4 | import { App } from './App';
5 | import './i18n';
6 | import { yupLocale } from './utils';
7 |
8 | import 'bootstrap/dist/css/bootstrap.min.css';
9 | import './index.css';
10 |
11 | yup.setLocale(yupLocale);
12 |
13 | ReactDOM.render(
14 |
15 |
16 | ,
17 | document.getElementById('root')
18 | );
19 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/Address.ts:
--------------------------------------------------------------------------------
1 | export interface Address {
2 | firstName: string;
3 | lastName: string;
4 | company?: string;
5 | address: string;
6 | city: string;
7 | state: string;
8 | zip: string;
9 | }
10 |
11 | export const newAddress = (): Address => ({
12 | firstName: '',
13 | lastName: '',
14 | company: '',
15 | address: '',
16 | city: '',
17 | state: '',
18 | zip: '',
19 | });
20 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/ContactInfo.ts:
--------------------------------------------------------------------------------
1 | export interface ContactInfo {
2 | email: string;
3 | }
4 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/Item.ts:
--------------------------------------------------------------------------------
1 | export interface Item {
2 | id: string;
3 | name: string;
4 | price: number;
5 | }
6 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/Order.ts:
--------------------------------------------------------------------------------
1 | import { Address } from './Address';
2 | import { ContactInfo } from './ContactInfo';
3 | import { OrderItem } from './OrderItem';
4 | import { PaymentMethod } from './PaymentMethod';
5 | import { ShippingOptions, ShippingRates } from './ShippingOptions';
6 |
7 | export interface Order {
8 | orderItems: Array;
9 | contactInfo: ContactInfo;
10 | shippingAddress: Address;
11 | shippingOptions: ShippingOptions;
12 | paymentMethod: PaymentMethod;
13 | }
14 |
15 | /* eslint-disable @typescript-eslint/no-redeclare */
16 | export const Order = {
17 | getOrderItemsTotal: (order: Order) => {
18 | return order.orderItems.reduce((total, orderItem) => {
19 | return total + OrderItem.getTotal(orderItem);
20 | }, 0);
21 | },
22 |
23 | getShippingCharges: (order: Order) => {
24 | return ShippingRates[order.shippingOptions.shippingMethod];
25 | },
26 |
27 | getOrderTotal: (order: Order) => {
28 | const orderItemsTotal = Order.getOrderItemsTotal(order);
29 | const shippingCharges = Order.getShippingCharges(order);
30 | return {
31 | orderItemsTotal,
32 | shippingCharges,
33 | orderTotal: orderItemsTotal + shippingCharges,
34 | };
35 | },
36 | };
37 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/OrderItem.ts:
--------------------------------------------------------------------------------
1 | import { Item } from './Item';
2 |
3 | export interface OrderItem {
4 | item: Item;
5 | qty: number;
6 | }
7 |
8 | /* eslint-disable @typescript-eslint/no-redeclare */
9 | export const OrderItem = {
10 | getTotal: (orderItem: OrderItem) => orderItem.item.price * orderItem.qty,
11 | };
12 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/PaymentMethod.ts:
--------------------------------------------------------------------------------
1 | export type PaymentType = 'creditCard' | 'bankAccount';
2 |
3 | export interface CreditCardPayment {
4 | type: 'creditCard';
5 | nameOnCard: string;
6 | cardNumber: string;
7 | expiration: string;
8 | cvv: number;
9 | }
10 |
11 | export interface BankAccountPayment {
12 | type: 'bankAccount';
13 | accountHolderName: string;
14 | bankName: string;
15 | routingNumber: string;
16 | accountNumber: string;
17 | }
18 |
19 | /** TypeScript discriminated union */
20 | export type PaymentMethod = CreditCardPayment | BankAccountPayment;
21 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/ShippingOptions.ts:
--------------------------------------------------------------------------------
1 | export type ShippingMethod = 'ground' | 'secondDay' | 'overnight';
2 |
3 | export const ShippingRates: { [key in ShippingMethod]: number } = {
4 | ground: 20.0,
5 | secondDay: 40.0,
6 | overnight: 60.0,
7 | };
8 |
9 | export interface ShippingOptions {
10 | shippingMethod: ShippingMethod;
11 | giftWrapping: boolean;
12 | }
13 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/ValidationError.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Validation Error
3 | *
4 | * Example:
5 | * {
6 | * key: 'validations.stringMin',
7 | * values: {
8 | * min: 2
9 | * }
10 | * }
11 | *
12 | * Assume that the key maps into the following tokenized error message
13 | * Must be at least {{min}} characters
14 | *
15 | * Then the final error message will be
16 | * Must be at least 2 characters
17 | */
18 | export interface ValidationError {
19 | /** key into translation file */
20 | key: string;
21 |
22 | /** token values */
23 | values?: { [key: string]: any };
24 | }
25 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/models/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Address';
2 | export * from './ContactInfo';
3 | export * from './Item';
4 | export * from './Order';
5 | export * from './OrderItem';
6 | export * from './PaymentMethod';
7 | export * from './ShippingOptions';
8 | export * from './ValidationError';
9 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/pages/CheckoutPage/CheckoutActions.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { NumberUtils } from '@react-force/number-utils';
3 | import { useTranslation } from 'react-i18next';
4 |
5 | export interface CheckoutActionsProps {
6 | orderTotal: number;
7 | }
8 |
9 | export const CheckoutActions = ({ orderTotal }: CheckoutActionsProps) => {
10 | const { t } = useTranslation();
11 | const orderTotalStr = NumberUtils.formatAsMoney(orderTotal);
12 |
13 | return (
14 |
15 |
18 |
19 | {t('text.orderTotal')}: ${orderTotalStr}
20 |
21 |
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/pages/CheckoutPage/CheckoutForm.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { yupResolver } from '@hookform/resolvers/yup';
3 | import { FormProvider, useForm } from 'react-hook-form';
4 | import { useTranslation } from 'react-i18next';
5 | import * as yup from 'yup';
6 | import { Order, ShippingMethod } from '../../models';
7 | import {
8 | AddressForm,
9 | getAddressSchema,
10 | ContactInfoForm,
11 | getContactInfoSchema,
12 | PaymentForm,
13 | getPaymentSchema,
14 | ShippingOptionsForm,
15 | shippingOptionsSchema,
16 | } from '../../components';
17 | import { CheckoutActions } from './CheckoutActions';
18 |
19 | export interface CheckoutFormProps {
20 | order: Order;
21 | onSubmit: (order: Order) => void;
22 | onShippingMethodChanged: (shippingMethod: ShippingMethod) => void;
23 | }
24 |
25 | export const CheckoutForm = ({
26 | order,
27 | onSubmit,
28 | onShippingMethodChanged,
29 | }: CheckoutFormProps) => {
30 | const schema = yup.object().shape({
31 | contactInfo: getContactInfoSchema(),
32 | shippingAddress: getAddressSchema(),
33 | shippingOptions: shippingOptionsSchema,
34 | paymentMethod: getPaymentSchema(),
35 | });
36 |
37 | const { t } = useTranslation();
38 | const methods = useForm({
39 | mode: 'onBlur',
40 | defaultValues: order,
41 | resolver: yupResolver(schema),
42 | });
43 |
44 | return (
45 |
46 |
67 |
68 | );
69 | };
70 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/pages/CheckoutPage/CheckoutPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { OrderDetail, OrderSummary } from '../../components';
3 | import { useOrder, useOrderSetter } from '../../contexts';
4 | import { Order, ShippingMethod } from '../../models';
5 | import { CheckoutForm } from './CheckoutForm';
6 |
7 | export const CheckoutPage = () => {
8 | const order = useOrder();
9 | const setOrder = useOrderSetter();
10 |
11 | /**
12 | * Note that `changedOrder` does not have orderItems,
13 | * so it must be merged with existing order.
14 | */
15 | const handleSubmit = (changedOrder: Order) => {
16 | console.log(JSON.stringify(changedOrder, null, 2));
17 | setOrder({
18 | ...order,
19 | ...changedOrder,
20 | });
21 | };
22 |
23 | const handleShippingMethodChanged = (shippingMethod: ShippingMethod) => {
24 | setOrder({
25 | ...order,
26 | shippingOptions: {
27 | ...order.shippingOptions,
28 | shippingMethod,
29 | },
30 | });
31 | };
32 |
33 | return (
34 |
49 | );
50 | };
51 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/pages/CheckoutPage/index.ts:
--------------------------------------------------------------------------------
1 | export * from './CheckoutPage';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/pages/index.ts:
--------------------------------------------------------------------------------
1 | export * from './CheckoutPage';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/stories/AddressForm.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState } from 'react';
2 | import { yupResolver } from '@hookform/resolvers/yup';
3 | import { StringUtils } from '@react-force/utils';
4 | import { Meta } from '@storybook/react/types-6-0';
5 | import { FormProvider, useForm } from 'react-hook-form';
6 | import { useTranslation } from 'react-i18next';
7 | import * as yup from 'yup';
8 | import {
9 | AddressForm,
10 | getAddressSchema,
11 | AddressView,
12 | Checkbox,
13 | } from '../components';
14 | import { address as InitialBillingAddress } from '../data';
15 | import { Address, newAddress } from '../models';
16 |
17 | const { isBlank } = StringUtils;
18 |
19 | export default {
20 | title: 'AddressForm',
21 | component: AddressForm,
22 | } as Meta;
23 |
24 | // -----------------------------
25 | // Single Address Story
26 | // -----------------------------
27 | interface Company {
28 | address: Address;
29 | }
30 |
31 | export const SingleAddressStory = () => {
32 | const [company, setCompany] = useState({
33 | address: newAddress(),
34 | });
35 | const { address } = company;
36 |
37 | const companySchema = yup.object().shape({
38 | address: getAddressSchema(),
39 | });
40 |
41 | const methods = useForm({
42 | mode: 'onBlur',
43 | defaultValues: company,
44 | resolver: yupResolver(companySchema),
45 | });
46 | const { handleSubmit } = methods;
47 |
48 | const onSubmit = (changedCompany: Company) => {
49 | setCompany(changedCompany);
50 | };
51 |
52 | return (
53 |
54 |
55 |
64 |
65 |
66 |
Form Values
67 | {!isBlank(address.firstName) ? (
68 |
69 | ) : null}
70 |
71 |
72 | );
73 | };
74 | SingleAddressStory.storyName = 'Single Address';
75 |
76 | // -----------------------------
77 | // Multiple Address Story
78 | // -----------------------------
79 | interface Order {
80 | isShippingAddressSameAsBilling: boolean;
81 | billingAddress: Address;
82 | shippingAddress: Address;
83 | }
84 |
85 | export const MultipleAddressStory = () => {
86 | const { t } = useTranslation();
87 | const [order, setOrder] = useState({
88 | isShippingAddressSameAsBilling: false,
89 | billingAddress: InitialBillingAddress,
90 | shippingAddress: newAddress(),
91 | });
92 | const { billingAddress, shippingAddress } = order;
93 | const addressSchema = getAddressSchema();
94 | const orderSchema = yup.lazy((value) => {
95 | const order = value as Order;
96 | return yup.object().shape({
97 | isShippingAddressSameAsBilling: yup.boolean().required(),
98 | billingAddress: addressSchema,
99 | shippingAddress: order.isShippingAddressSameAsBilling
100 | ? yup.mixed().notRequired()
101 | : addressSchema,
102 | });
103 | });
104 |
105 | const methods = useForm({
106 | mode: 'onBlur',
107 | defaultValues: order,
108 | resolver: yupResolver(orderSchema),
109 | });
110 | const { errors, handleSubmit, register } = methods;
111 |
112 | const { watch } = methods;
113 | const isShippingAddressSameAsBilling = watch(
114 | 'isShippingAddressSameAsBilling'
115 | );
116 |
117 | const onSubmit = (changedOrder: Order) => {
118 | setOrder(changedOrder);
119 | };
120 |
121 | return (
122 |
123 |
124 |
152 |
153 |
154 |
Form Values
155 |
156 |
157 | {!isBlank(billingAddress.firstName) ? (
158 |
162 | ) : null}
163 |
164 |
165 | {!isBlank(shippingAddress?.firstName) ? (
166 |
170 | ) : null}
171 |
172 |
173 |
174 |
175 | );
176 | };
177 | MultipleAddressStory.storyName = 'Multiple Address';
178 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/stories/ContactInfoForm.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState } from 'react';
2 | import { yupResolver } from '@hookform/resolvers/yup';
3 | import { Meta } from '@storybook/react/types-6-0';
4 | import { FormProvider, useForm } from 'react-hook-form';
5 | import * as yup from 'yup';
6 | import { ContactInfoForm, getContactInfoSchema } from '../components';
7 | import { ContactInfo } from '../models';
8 |
9 | export default {
10 | title: 'ContactInfoForm',
11 | component: ContactInfoForm,
12 | } as Meta;
13 |
14 | interface Order {
15 | contactInfo: ContactInfo;
16 | }
17 |
18 | export const ContactInfoFormStory = () => {
19 | const [order, setOrder] = useState({
20 | contactInfo: {
21 | email: '',
22 | },
23 | });
24 | const { contactInfo } = order;
25 |
26 | const orderSchema = yup.object().shape({
27 | contactInfo: getContactInfoSchema(),
28 | });
29 | const methods = useForm({
30 | mode: 'onBlur',
31 | defaultValues: order,
32 | resolver: yupResolver(orderSchema),
33 | });
34 | const { handleSubmit } = methods;
35 |
36 | const onSubmit = (changedOrder: Order) => {
37 | setOrder(changedOrder);
38 | };
39 |
40 | return (
41 |
42 |
43 |
52 |
53 |
54 |
Form Values
55 |
{contactInfo.email}
56 |
57 |
58 | );
59 | };
60 | ContactInfoFormStory.storyName = 'ContactInfoForm';
61 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/stories/LimitedTextField.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta } from '@storybook/react/types-6-0';
3 | import { LimitedTextField } from '../components';
4 |
5 | export default {
6 | title: 'LimitedTextField',
7 | component: LimitedTextField,
8 | } as Meta;
9 |
10 | export const LimitedTextFieldStory = () => ;
11 | LimitedTextFieldStory.storyName = 'LimitedTextField';
12 |
13 | // ----- NOTE: Template syntax below does not work -----
14 | // const Template: Story = (args) => (
15 | //
16 | // );
17 | //
18 | // export const LimitedTextFieldStory = Template.bind({});
19 | // LimitedTextFieldStory.args = {
20 | // maxCount: 30,
21 | // };
22 | // LimitedTextFieldStory.storyName = 'LimitedTextField';
23 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/stories/PaymentForm.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState } from 'react';
2 | import { yupResolver } from '@hookform/resolvers/yup';
3 | import { Meta } from '@storybook/react/types-6-0';
4 | import { FormProvider, useForm } from 'react-hook-form';
5 | import * as yup from 'yup';
6 | import { PaymentForm, getPaymentSchema, PaymentView } from '../components';
7 | import { PaymentMethod } from '../models';
8 |
9 | export default {
10 | title: 'PaymentForm',
11 | component: PaymentForm,
12 | } as Meta;
13 |
14 | interface Order {
15 | paymentMethod: PaymentMethod;
16 | }
17 |
18 | export const PaymentFormStory = () => {
19 | const [order, setOrder] = useState({
20 | paymentMethod: {
21 | type: 'creditCard',
22 | nameOnCard: '',
23 | cardNumber: '',
24 | expiration: '',
25 | cvv: 0,
26 | },
27 | });
28 | const { paymentMethod } = order;
29 |
30 | const orderSchema = yup.object().shape({
31 | paymentMethod: getPaymentSchema(),
32 | });
33 | const methods = useForm({
34 | mode: 'onBlur',
35 | defaultValues: order,
36 | resolver: yupResolver(orderSchema),
37 | });
38 | const { handleSubmit } = methods;
39 |
40 | const onSubmit = (changedOrder: Order) => {
41 | setOrder(changedOrder);
42 | };
43 |
44 | return (
45 |
46 |
47 |
56 |
57 |
58 |
Form Values
59 |
60 |
61 |
62 | );
63 | };
64 | PaymentFormStory.storyName = 'PaymentForm';
65 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/stories/ShippingOptionsForm.stories.tsx:
--------------------------------------------------------------------------------
1 | import React, { Fragment, useState } from 'react';
2 | import { yupResolver } from '@hookform/resolvers/yup';
3 | import { Meta } from '@storybook/react/types-6-0';
4 | import { FormProvider, useForm } from 'react-hook-form';
5 | import { useTranslation } from 'react-i18next';
6 | import * as yup from 'yup';
7 | import {
8 | ShippingMethodText,
9 | ShippingOptionsForm,
10 | shippingOptionsSchema,
11 | } from '../components';
12 | import { ShippingOptions } from '../models';
13 |
14 | export default {
15 | title: 'ShippingOptionsForm',
16 | component: ShippingOptionsForm,
17 | } as Meta;
18 |
19 | interface Order {
20 | shippingOptions: ShippingOptions;
21 | }
22 |
23 | const orderSchema = yup.object().shape({
24 | shippingOptions: shippingOptionsSchema,
25 | });
26 |
27 | export const ShippingOptionsFormStory = () => {
28 | const { t } = useTranslation();
29 | const [order, setOrder] = useState({
30 | shippingOptions: {
31 | shippingMethod: 'ground',
32 | giftWrapping: false,
33 | },
34 | });
35 | const { shippingOptions } = order;
36 |
37 | const methods = useForm({
38 | mode: 'onBlur',
39 | defaultValues: order,
40 | resolver: yupResolver(orderSchema),
41 | });
42 | const { handleSubmit } = methods;
43 |
44 | const onSubmit = (changedOrder: Order) => {
45 | setOrder(changedOrder);
46 | };
47 |
48 | return (
49 |
50 |
51 |
60 |
61 |
62 |
Form Values
63 |
64 | {t('text.shippingMethod')}:{' '}
65 |
68 |
69 | {t('text.giftWrapping')}:{' '}
70 | {shippingOptions.giftWrapping
71 | ? t('text.yes')
72 | : t('text.no')}
73 |
74 |
75 |
76 | );
77 | };
78 | ShippingOptionsFormStory.storyName = 'ShippingOptionsForm';
79 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/stories/TextField.stories.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Meta } from '@storybook/react/types-6-0';
3 | import { TextField } from '../components';
4 |
5 | export default {
6 | title: 'TextField',
7 | component: TextField,
8 | } as Meta;
9 |
10 | export const TextFieldStory = () => ;
11 | TextFieldStory.storyName = 'TextField';
12 |
13 | export const TextFieldErrorStory = () => {
14 | return (
15 |
24 | );
25 | };
26 | TextFieldErrorStory.storyName = 'TextField Error';
27 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | export * from './yupLocale';
2 |
--------------------------------------------------------------------------------
/checkout-form-rhf/src/utils/yupLocale.ts:
--------------------------------------------------------------------------------
1 | // @ts-nocheck (to ignore typechecking on validation function parameters)
2 | export const yupLocale = {
3 | mixed: {
4 | default: {
5 | key: 'validations.invalid',
6 | },
7 | required: {
8 | key: 'validations.required',
9 | },
10 | notType: ({ type }) => ({
11 | key: 'validations.invalidType',
12 | values: { type },
13 | }),
14 | },
15 | string: {
16 | email: {
17 | key: 'validations.email',
18 | },
19 | min: ({ min }) => ({
20 | key: 'validations.stringMin',
21 | values: { min },
22 | }),
23 | max: ({ max }) => ({
24 | key: 'validations.stringMax',
25 | values: { max },
26 | }),
27 | },
28 | number: {},
29 | boolean: {},
30 | };
31 |
--------------------------------------------------------------------------------
/checkout-form-rhf/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "dom",
6 | "dom.iterable",
7 | "esnext"
8 | ],
9 | "allowJs": true,
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "noFallthroughCasesInSwitch": true,
14 | "strict": true,
15 | "forceConsistentCasingInFileNames": true,
16 | "module": "esnext",
17 | "moduleResolution": "node",
18 | "resolveJsonModule": true,
19 | "isolatedModules": true,
20 | "noEmit": true,
21 | "jsx": "react-jsx"
22 | },
23 | "include": [
24 | "src"
25 | ]
26 | }
27 |
--------------------------------------------------------------------------------
/docs/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "main.css": "./static/css/main.cf37a24c.chunk.css",
4 | "main.js": "./main.22514c02e870346d0f24.bundle.js",
5 | "main.css.map": "./static/css/main.cf37a24c.chunk.css.map",
6 | "main.js.map": "./main.22514c02e870346d0f24.bundle.js.map",
7 | "runtime~main.js": "./runtime~main.22514c02e870346d0f24.bundle.js",
8 | "runtime~main.js.map": "./runtime~main.22514c02e870346d0f24.bundle.js.map",
9 | "vendors~main.css": "./static/css/vendors~main.20aa2d7b.chunk.css",
10 | "vendors~main.js": "./vendors~main.22514c02e870346d0f24.bundle.js",
11 | "vendors~main.css.map": "./static/css/vendors~main.20aa2d7b.chunk.css.map",
12 | "vendors~main.js.map": "./vendors~main.22514c02e870346d0f24.bundle.js.map",
13 | "iframe.html": "./iframe.html",
14 | "static/media/getFetch.cjs": "./static/media/getFetch.d7d6010d.cjs",
15 | "vendors~main.22514c02e870346d0f24.bundle.js.LICENSE.txt": "./vendors~main.22514c02e870346d0f24.bundle.js.LICENSE.txt"
16 | },
17 | "entrypoints": [
18 | "runtime~main.22514c02e870346d0f24.bundle.js",
19 | "static/css/vendors~main.20aa2d7b.chunk.css",
20 | "vendors~main.22514c02e870346d0f24.bundle.js",
21 | "static/css/main.cf37a24c.chunk.css",
22 | "main.22514c02e870346d0f24.bundle.js"
23 | ]
24 | }
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nareshbhatia/form-examples/17f3ef2c9908ccbe620804831addb63e39155389/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/iframe.html:
--------------------------------------------------------------------------------
1 | StorybookNo Preview
Sorry, but you either have no stories or none are selected somehow.
- Please check the Storybook config.
- Try reloading the page.
If the problem persists, check the browser console, or the terminal you've run Storybook from.
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 | Storybook
--------------------------------------------------------------------------------
/docs/locales/en/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "text": {
3 | "accountHolderName": "Account holder's name",
4 | "accountNumber": "Account number",
5 | "address": "Address",
6 | "bankAccount": "Bank Account",
7 | "bankName": "Bank name",
8 | "billingAddress": "Billing Address",
9 | "cardNumber": "Card number",
10 | "characters": "characters",
11 | "checkout": "Checkout",
12 | "city": "City",
13 | "companyOptional": "Company (optional)",
14 | "contactInfo": "Contact Information",
15 | "creditCard": "Credit Card",
16 | "creditCardNumber": "Credit card number",
17 | "cvv": "CVV",
18 | "email": "Email",
19 | "expiration": "Expiration",
20 | "firstName": "First name",
21 | "giftWrapping": "Gift wrapping",
22 | "ground": "Ground",
23 | "groundLong": "Ground (3-5 days)",
24 | "items": "Items",
25 | "lastName": "Last name",
26 | "nameOnCard": "Name on card",
27 | "no": "No",
28 | "overnight": "Overnight",
29 | "orderDetail": "Order Detail",
30 | "orderTotal": "Order total",
31 | "orderSummary": "Order Summary",
32 | "paymentMethod": "Payment Method",
33 | "placeYourOrder": "Place your order",
34 | "quantity": "Quantity",
35 | "routingNumber": "Routing number",
36 | "secondDay": "Second Day",
37 | "shippingAddress": "Shipping Address",
38 | "shippingHandling": "Shipping & handling",
39 | "shippingMethod": "Shipping method",
40 | "shippingOptions": "Shipping Options",
41 | "state": "State",
42 | "yes": "Yes",
43 | "zip": "Zip"
44 | },
45 | "validations": {
46 | "email": "Email is invalid",
47 | "invalid": "Field is invalid",
48 | "invalidType": "Must be a {{type}}",
49 | "required": "Field is required",
50 | "stringMin": "Must be at least {{min}} characters",
51 | "stringMax": "Must be at most {{max}} characters"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/docs/locales/es/translation.json:
--------------------------------------------------------------------------------
1 | {
2 | "text": {
3 | "accountHolderName": "Nombre del titular de la cuenta",
4 | "accountNumber": "Número de cuenta",
5 | "address": "Dirección",
6 | "bankAccount": "Cuenta Bancaria",
7 | "bankName": "Nombre del banco",
8 | "billingAddress": "Dirección de Facturación",
9 | "cardNumber": "Número de tarjeta",
10 | "characters": "caracteres",
11 | "checkout": "Revisa",
12 | "city": "Ciudad",
13 | "companyOptional": "Companía (opcional)",
14 | "contactInfo": "Información del Contacto",
15 | "creditCard": "Tarjeta de Crédito",
16 | "creditCardNumber": "Número de tarjeta de crédito",
17 | "cvv": "CVV",
18 | "email": "Email",
19 | "expiration": "Vencimiento",
20 | "firstName": "Primer nombre",
21 | "giftWrapping": "Envoltorio de Regalo",
22 | "ground": "Suelo",
23 | "groundLong": "Suelo (3-5 días)",
24 | "items": "Artículos",
25 | "lastName": "Apellido",
26 | "nameOnCard": "Nombre en la tarjeta",
27 | "no": "No",
28 | "orderDetail": "Detalle de la orden",
29 | "orderTotal": "Total del pedido",
30 | "orderSummary": "Resumen del pedido",
31 | "overnight": "Durante la noche",
32 | "paymentMethod": "Método de Pago",
33 | "placeYourOrder": "Haga su pedido",
34 | "quantity": "Cantidad",
35 | "routingNumber": "Número de ruta",
36 | "secondDay": "Segundo Día",
37 | "shippingAddress": "Dirección de Envío",
38 | "shippingHandling": "Envío y manejo",
39 | "shippingMethod": "Método de envío",
40 | "shippingOptions": "Opciones de Envío",
41 | "state": "Estado",
42 | "yes": "Si",
43 | "zip": "Código Postal"
44 | },
45 | "validations": {
46 | "email": "El correo electrónico es invalido",
47 | "invalid": "El campo no es válido",
48 | "invalidType": "Tiene que ser un {{type}}",
49 | "required": "Se requiere campo",
50 | "stringMin": "Debe tener al menos {{min}} caracteres",
51 | "stringMax": "Debe tener como máximo {{max}} caracteres"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/docs/main.22514c02e870346d0f24.bundle.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[0],{1120:function(module,exports,__webpack_require__){"use strict";var _clientApi=__webpack_require__(60),_clientLogger=__webpack_require__(39),_configFilename=__webpack_require__(1145);function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);enumerableOnly&&(symbols=symbols.filter((function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable}))),keys.push.apply(keys,symbols)}return keys}function _objectSpread(target){for(var i=1;i {\n const [order, setOrder] = useState({\n contactInfo: {\n email: \'\',\n },\n });\n const { contactInfo } = order;\n\n const orderSchema = yup.object().shape({\n contactInfo: getContactInfoSchema(),\n });\n const methods = useForm({\n mode: \'onBlur\',\n defaultValues: order,\n resolver: yupResolver(orderSchema),\n });\n const { handleSubmit } = methods;\n\n const onSubmit = (changedOrder: Order) => {\n setOrder(changedOrder);\n };\n\n return (\n \n \n \n \n \n
Form Values
\n
{contactInfo.email}
\n
\n \n );\n}'}},ContactInfoFormStory.parameters)},1138:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,"LimitedTextFieldStory",(function(){return LimitedTextFieldStory}));var _Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(30),react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(1),_components__WEBPACK_IMPORTED_MODULE_3__=(__webpack_require__(0),__webpack_require__(27));__webpack_exports__.default={title:"LimitedTextField",component:_components__WEBPACK_IMPORTED_MODULE_3__.e};var LimitedTextFieldStory=function LimitedTextFieldStory(){return Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(_components__WEBPACK_IMPORTED_MODULE_3__.e,{maxCount:10})};LimitedTextFieldStory.storyName="LimitedTextField",LimitedTextFieldStory.parameters=Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)({storySource:{source:"() => "}},LimitedTextFieldStory.parameters)},1139:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,"PaymentFormStory",(function(){return PaymentFormStory}));var _Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(30),react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(1),_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_slicedToArray__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__(80),react__WEBPACK_IMPORTED_MODULE_3__=__webpack_require__(0),_hookform_resolvers_yup__WEBPACK_IMPORTED_MODULE_4__=__webpack_require__(99),react_hook_form__WEBPACK_IMPORTED_MODULE_5__=__webpack_require__(33),yup__WEBPACK_IMPORTED_MODULE_6__=__webpack_require__(14),_components__WEBPACK_IMPORTED_MODULE_7__=__webpack_require__(27);__webpack_exports__.default={title:"PaymentForm",component:_components__WEBPACK_IMPORTED_MODULE_7__.g};var PaymentFormStory=function PaymentFormStory(){var _useState=Object(react__WEBPACK_IMPORTED_MODULE_3__.useState)({paymentMethod:{type:"creditCard",nameOnCard:"",cardNumber:"",expiration:"",cvv:0}}),_useState2=Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_slicedToArray__WEBPACK_IMPORTED_MODULE_2__.a)(_useState,2),order=_useState2[0],setOrder=_useState2[1],paymentMethod=order.paymentMethod,orderSchema=yup__WEBPACK_IMPORTED_MODULE_6__.e().shape({paymentMethod:Object(_components__WEBPACK_IMPORTED_MODULE_7__.n)()}),methods=Object(react_hook_form__WEBPACK_IMPORTED_MODULE_5__.useForm)({mode:"onBlur",defaultValues:order,resolver:Object(_hookform_resolvers_yup__WEBPACK_IMPORTED_MODULE_4__.yupResolver)(orderSchema)}),handleSubmit=methods.handleSubmit;return Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxs)(react__WEBPACK_IMPORTED_MODULE_3__.Fragment,{children:[Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(react_hook_form__WEBPACK_IMPORTED_MODULE_5__.FormProvider,Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)(Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)({},methods),{},{children:Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxs)("form",{onSubmit:handleSubmit((function onSubmit(changedOrder){setOrder(changedOrder)})),children:[Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(_components__WEBPACK_IMPORTED_MODULE_7__.g,{}),Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("div",{className:"mt-2",children:Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("button",{className:"btn btn-primary",type:"submit",children:"Submit"})})]})})),Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxs)("div",{className:"mt-4",children:[Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("h5",{className:"mb-2",children:"Form Values"}),Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(_components__WEBPACK_IMPORTED_MODULE_7__.h,{paymentMethod:paymentMethod})]})]})};PaymentFormStory.storyName="PaymentForm",PaymentFormStory.parameters=Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)({storySource:{source:"() => {\n const [order, setOrder] = useState({\n paymentMethod: {\n type: 'creditCard',\n nameOnCard: '',\n cardNumber: '',\n expiration: '',\n cvv: 0,\n },\n });\n const { paymentMethod } = order;\n\n const orderSchema = yup.object().shape({\n paymentMethod: getPaymentSchema(),\n });\n const methods = useForm({\n mode: 'onBlur',\n defaultValues: order,\n resolver: yupResolver(orderSchema),\n });\n const { handleSubmit } = methods;\n\n const onSubmit = (changedOrder: Order) => {\n setOrder(changedOrder);\n };\n\n return (\n \n \n \n \n \n \n );\n}"}},PaymentFormStory.parameters)},1140:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,"ShippingOptionsFormStory",(function(){return ShippingOptionsFormStory}));var _Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(30),react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(1),_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_slicedToArray__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__(80),react__WEBPACK_IMPORTED_MODULE_3__=__webpack_require__(0),_hookform_resolvers_yup__WEBPACK_IMPORTED_MODULE_4__=__webpack_require__(99),react_hook_form__WEBPACK_IMPORTED_MODULE_5__=__webpack_require__(33),react_i18next__WEBPACK_IMPORTED_MODULE_6__=__webpack_require__(1149),yup__WEBPACK_IMPORTED_MODULE_7__=__webpack_require__(14),_components__WEBPACK_IMPORTED_MODULE_8__=__webpack_require__(27);__webpack_exports__.default={title:"ShippingOptionsForm",component:_components__WEBPACK_IMPORTED_MODULE_8__.j};var orderSchema=yup__WEBPACK_IMPORTED_MODULE_7__.e().shape({shippingOptions:_components__WEBPACK_IMPORTED_MODULE_8__.o}),ShippingOptionsFormStory=function ShippingOptionsFormStory(){var t=Object(react_i18next__WEBPACK_IMPORTED_MODULE_6__.a)().t,_useState=Object(react__WEBPACK_IMPORTED_MODULE_3__.useState)({shippingOptions:{shippingMethod:"ground",giftWrapping:!1}}),_useState2=Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_slicedToArray__WEBPACK_IMPORTED_MODULE_2__.a)(_useState,2),order=_useState2[0],setOrder=_useState2[1],shippingOptions=order.shippingOptions,methods=Object(react_hook_form__WEBPACK_IMPORTED_MODULE_5__.useForm)({mode:"onBlur",defaultValues:order,resolver:Object(_hookform_resolvers_yup__WEBPACK_IMPORTED_MODULE_4__.yupResolver)(orderSchema)}),handleSubmit=methods.handleSubmit;return Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxs)(react__WEBPACK_IMPORTED_MODULE_3__.Fragment,{children:[Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(react_hook_form__WEBPACK_IMPORTED_MODULE_5__.FormProvider,Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)(Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)({},methods),{},{children:Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxs)("form",{onSubmit:handleSubmit((function onSubmit(changedOrder){setOrder(changedOrder)})),children:[Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(_components__WEBPACK_IMPORTED_MODULE_8__.j,{onShippingMethodChanged:function onShippingMethodChanged(){}}),Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("div",{className:"mt-3",children:Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("button",{className:"btn btn-primary",type:"submit",children:"Submit"})})]})})),Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxs)("div",{className:"mt-4",children:[Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("h5",{className:"mb-2",children:"Form Values"}),Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsxs)("p",{children:[t("text.shippingMethod"),":"," ",Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(_components__WEBPACK_IMPORTED_MODULE_8__.i,{shippingMethod:shippingOptions.shippingMethod}),Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("br",{}),t("text.giftWrapping"),":"," ",shippingOptions.giftWrapping?t("text.yes"):t("text.no")]})]})]})};ShippingOptionsFormStory.storyName="ShippingOptionsForm",ShippingOptionsFormStory.parameters=Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)({storySource:{source:"() => {\n const { t } = useTranslation();\n const [order, setOrder] = useState({\n shippingOptions: {\n shippingMethod: 'ground',\n giftWrapping: false,\n },\n });\n const { shippingOptions } = order;\n\n const methods = useForm({\n mode: 'onBlur',\n defaultValues: order,\n resolver: yupResolver(orderSchema),\n });\n const { handleSubmit } = methods;\n\n const onSubmit = (changedOrder: Order) => {\n setOrder(changedOrder);\n };\n\n return (\n \n \n \n \n \n
Form Values
\n
\n {t('text.shippingMethod')}:{' '}\n \n
\n {t('text.giftWrapping')}:{' '}\n {shippingOptions.giftWrapping\n ? t('text.yes')\n : t('text.no')}\n
\n
\n \n );\n}"}},ShippingOptionsFormStory.parameters)},1141:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,"TextFieldStory",(function(){return TextFieldStory})),__webpack_require__.d(__webpack_exports__,"TextFieldErrorStory",(function(){return TextFieldErrorStory}));var _Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(30),react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(1),_components__WEBPACK_IMPORTED_MODULE_3__=(__webpack_require__(0),__webpack_require__(27));__webpack_exports__.default={title:"TextField",component:_components__WEBPACK_IMPORTED_MODULE_3__.k};var TextFieldStory=function TextFieldStory(){return Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(_components__WEBPACK_IMPORTED_MODULE_3__.k,{label:"Name"})};TextFieldStory.storyName="TextField";var TextFieldErrorStory=function TextFieldErrorStory(){return Object(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)(_components__WEBPACK_IMPORTED_MODULE_3__.k,{label:"Name",error:{key:"validations.stringMin",values:{min:2}}})};TextFieldErrorStory.storyName="TextField Error",TextFieldStory.parameters=Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)({storySource:{source:'() => '}},TextFieldStory.parameters),TextFieldErrorStory.parameters=Object(_Users_naresh_projects_form_examples_checkout_form_rhf_node_modules_babel_preset_react_app_node_modules_babel_runtime_helpers_esm_objectSpread2__WEBPACK_IMPORTED_MODULE_0__.a)({storySource:{source:"() => {\n return (\n \n );\n}"}},TextFieldErrorStory.parameters)},1145:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,"parameters",(function(){return parameters}));var jsx_runtime=__webpack_require__(1),react=__webpack_require__(0),client=__webpack_require__(223),es=__webpack_require__(14),i18next=__webpack_require__(339),context=__webpack_require__(171),esm=__webpack_require__(508);i18next.a.use(esm.a).use(context.e).init({lng:"en",debug:!0,interpolation:{escapeValue:!1}});i18next.a;var components=__webpack_require__(27);__webpack_require__(1131),__webpack_require__(1132);es.f({mixed:{default:{key:"validations.invalid"},required:{key:"validations.required"},notType:function notType(_ref){return{key:"validations.invalidType",values:{type:_ref.type}}}},string:{email:{key:"validations.email"},min:function min(_ref2){return{key:"validations.stringMin",values:{min:_ref2.min}}},max:function max(_ref3){return{key:"validations.stringMax",values:{max:_ref3.max}}}},number:{},boolean:{}});var parameters={actions:{argTypesRegex:"^on[A-Z].*"}};Object(client.addDecorator)((function StoryDecorator(Story){return Object(jsx_runtime.jsx)(react.Suspense,{fallback:Object(jsx_runtime.jsx)(components.f,{}),children:Object(jsx_runtime.jsx)(Story,{})})}))},1146:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__),__webpack_require__.d(__webpack_exports__,"SingleAddressStory",(function(){return AddressForm_stories_SingleAddressStory})),__webpack_require__.d(__webpack_exports__,"MultipleAddressStory",(function(){return AddressForm_stories_MultipleAddressStory}));var objectSpread2=__webpack_require__(30),jsx_runtime=__webpack_require__(1),slicedToArray=__webpack_require__(80),react=__webpack_require__(0),yup=__webpack_require__(99),utils_esm=__webpack_require__(113),index_esm=__webpack_require__(33),useTranslation=__webpack_require__(1149),es=__webpack_require__(14),components=__webpack_require__(27),address_address={firstName:"Elon",lastName:"Musk",company:"Tesla, Inc.",address:" 3500 Deer Creek Road",city:"Palo Alto",state:"CA",zip:"94304"},models=__webpack_require__(141),isBlank=utils_esm.a.isBlank,AddressForm_stories_SingleAddressStory=(__webpack_exports__.default={title:"AddressForm",component:components.a},function SingleAddressStory(){var _useState=Object(react.useState)({address:Object(models.newAddress)()}),_useState2=Object(slicedToArray.a)(_useState,2),company=_useState2[0],setCompany=_useState2[1],address=company.address,companySchema=es.e().shape({address:Object(components.l)()}),methods=Object(index_esm.useForm)({mode:"onBlur",defaultValues:company,resolver:Object(yup.yupResolver)(companySchema)}),handleSubmit=methods.handleSubmit;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)(index_esm.FormProvider,Object(objectSpread2.a)(Object(objectSpread2.a)({},methods),{},{children:Object(jsx_runtime.jsxs)("form",{onSubmit:handleSubmit((function onSubmit(changedCompany){setCompany(changedCompany)})),children:[Object(jsx_runtime.jsx)(components.a,{title:"Address",parentName:"address"}),Object(jsx_runtime.jsx)("div",{className:"mt-2",children:Object(jsx_runtime.jsx)("button",{className:"btn btn-primary",type:"submit",children:"Submit"})})]})})),Object(jsx_runtime.jsxs)("div",{className:"mt-4",children:[Object(jsx_runtime.jsx)("h5",{className:"mb-2",children:"Form Values"}),isBlank(address.firstName)?null:Object(jsx_runtime.jsx)(components.b,{address:address})]})]})});AddressForm_stories_SingleAddressStory.storyName="Single Address";var AddressForm_stories_MultipleAddressStory=function MultipleAddressStory(){var _errors$isShippingAdd,t=Object(useTranslation.a)().t,_useState3=Object(react.useState)({isShippingAddressSameAsBilling:!1,billingAddress:address_address,shippingAddress:Object(models.newAddress)()}),_useState4=Object(slicedToArray.a)(_useState3,2),order=_useState4[0],setOrder=_useState4[1],billingAddress=order.billingAddress,shippingAddress=order.shippingAddress,addressSchema=Object(components.l)(),orderSchema=es.b((function(value){var order=value;return es.e().shape({isShippingAddressSameAsBilling:es.a().required(),billingAddress:addressSchema,shippingAddress:order.isShippingAddressSameAsBilling?es.c().notRequired():addressSchema})})),methods=Object(index_esm.useForm)({mode:"onBlur",defaultValues:order,resolver:Object(yup.yupResolver)(orderSchema)}),errors=methods.errors,handleSubmit=methods.handleSubmit,register=methods.register,isShippingAddressSameAsBilling=(0,methods.watch)("isShippingAddressSameAsBilling");return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)(index_esm.FormProvider,Object(objectSpread2.a)(Object(objectSpread2.a)({},methods),{},{children:Object(jsx_runtime.jsxs)("form",{onSubmit:handleSubmit((function onSubmit(changedOrder){setOrder(changedOrder)})),children:[Object(jsx_runtime.jsx)(components.a,{title:"Billing Address",parentName:"billingAddress"}),Object(jsx_runtime.jsx)("h5",{className:"mt-3 mb-2",children:t("text.shippingAddress")}),Object(jsx_runtime.jsx)("div",{className:"mb-3",children:Object(jsx_runtime.jsx)(components.c,{id:"isShippingAddressSameAsBilling",name:"isShippingAddressSameAsBilling",label:"Same as billing address",ref:register,error:null===(_errors$isShippingAdd=errors.isShippingAddressSameAsBilling)||void 0===_errors$isShippingAdd?void 0:_errors$isShippingAdd.message})}),isShippingAddressSameAsBilling?null:Object(jsx_runtime.jsx)(components.a,{parentName:"shippingAddress"}),Object(jsx_runtime.jsx)("div",{className:"mt-2",children:Object(jsx_runtime.jsx)("button",{className:"btn btn-primary",type:"submit",children:"Submit"})})]})})),Object(jsx_runtime.jsxs)("div",{className:"mt-4",children:[Object(jsx_runtime.jsx)("h5",{className:"mb-2",children:"Form Values"}),Object(jsx_runtime.jsxs)("div",{className:"row",children:[Object(jsx_runtime.jsx)("div",{className:"col-6",children:isBlank(billingAddress.firstName)?null:Object(jsx_runtime.jsx)(components.b,{label:t("text.billingAddress"),address:billingAddress})}),Object(jsx_runtime.jsx)("div",{className:"col-6",children:isBlank(null==shippingAddress?void 0:shippingAddress.firstName)?null:Object(jsx_runtime.jsx)(components.b,{label:t("text.shippingAddress"),address:shippingAddress})})]})]})]})};AddressForm_stories_MultipleAddressStory.storyName="Multiple Address",AddressForm_stories_SingleAddressStory.parameters=Object(objectSpread2.a)({storySource:{source:'() => {\n const [company, setCompany] = useState({\n address: newAddress(),\n });\n const { address } = company;\n\n const companySchema = yup.object().shape({\n address: getAddressSchema(),\n });\n\n const methods = useForm({\n mode: \'onBlur\',\n defaultValues: company,\n resolver: yupResolver(companySchema),\n });\n const { handleSubmit } = methods;\n\n const onSubmit = (changedCompany: Company) => {\n setCompany(changedCompany);\n };\n\n return (\n \n \n \n \n \n
Form Values
\n {!isBlank(address.firstName) ? (\n
\n ) : null}\n
\n \n );\n}'}},AddressForm_stories_SingleAddressStory.parameters),AddressForm_stories_MultipleAddressStory.parameters=Object(objectSpread2.a)({storySource:{source:'() => {\n const { t } = useTranslation();\n const [order, setOrder] = useState({\n isShippingAddressSameAsBilling: false,\n billingAddress: InitialBillingAddress,\n shippingAddress: newAddress(),\n });\n const { billingAddress, shippingAddress } = order;\n const addressSchema = getAddressSchema();\n const orderSchema = yup.lazy((value) => {\n const order = value as Order;\n return yup.object().shape({\n isShippingAddressSameAsBilling: yup.boolean().required(),\n billingAddress: addressSchema,\n shippingAddress: order.isShippingAddressSameAsBilling\n ? yup.mixed().notRequired()\n : addressSchema,\n });\n });\n\n const methods = useForm({\n mode: \'onBlur\',\n defaultValues: order,\n resolver: yupResolver(orderSchema),\n });\n const { errors, handleSubmit, register } = methods;\n\n const { watch } = methods;\n const isShippingAddressSameAsBilling = watch(\n \'isShippingAddressSameAsBilling\'\n );\n\n const onSubmit = (changedOrder: Order) => {\n setOrder(changedOrder);\n };\n\n return (\n \n \n \n \n \n
Form Values
\n
\n
\n {!isBlank(billingAddress.firstName) ? (\n
\n ) : null}\n
\n
\n {!isBlank(shippingAddress?.firstName) ? (\n
\n ) : null}\n
\n
\n
\n \n );\n}'}},AddressForm_stories_MultipleAddressStory.parameters)},141:function(module,__webpack_exports__,__webpack_require__){"use strict";var _Address__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(491);__webpack_require__.d(__webpack_exports__,"newAddress",(function(){return _Address__WEBPACK_IMPORTED_MODULE_0__.a}));var _ContactInfo__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(492);__webpack_require__.o(_ContactInfo__WEBPACK_IMPORTED_MODULE_1__,"Order")&&__webpack_require__.d(__webpack_exports__,"Order",(function(){return _ContactInfo__WEBPACK_IMPORTED_MODULE_1__.Order})),__webpack_require__.o(_ContactInfo__WEBPACK_IMPORTED_MODULE_1__,"OrderItem")&&__webpack_require__.d(__webpack_exports__,"OrderItem",(function(){return _ContactInfo__WEBPACK_IMPORTED_MODULE_1__.OrderItem}));var _Item__WEBPACK_IMPORTED_MODULE_2__=__webpack_require__(493);__webpack_require__.o(_Item__WEBPACK_IMPORTED_MODULE_2__,"Order")&&__webpack_require__.d(__webpack_exports__,"Order",(function(){return _Item__WEBPACK_IMPORTED_MODULE_2__.Order})),__webpack_require__.o(_Item__WEBPACK_IMPORTED_MODULE_2__,"OrderItem")&&__webpack_require__.d(__webpack_exports__,"OrderItem",(function(){return _Item__WEBPACK_IMPORTED_MODULE_2__.OrderItem}));var _Order__WEBPACK_IMPORTED_MODULE_3__=__webpack_require__(494);__webpack_require__.d(__webpack_exports__,"Order",(function(){return _Order__WEBPACK_IMPORTED_MODULE_3__.a}));var _OrderItem__WEBPACK_IMPORTED_MODULE_4__=__webpack_require__(225);__webpack_require__.d(__webpack_exports__,"OrderItem",(function(){return _OrderItem__WEBPACK_IMPORTED_MODULE_4__.a}));__webpack_require__(495),__webpack_require__(226),__webpack_require__(496)},225:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.d(__webpack_exports__,"a",(function(){return OrderItem}));var OrderItem={getTotal:function getTotal(orderItem){return orderItem.item.price*orderItem.qty}}},226:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.d(__webpack_exports__,"a",(function(){return ShippingRates}));var ShippingRates={ground:20,secondDay:40,overnight:60}},27:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.d(__webpack_exports__,"l",(function(){return AddressForm_getAddressSchema})),__webpack_require__.d(__webpack_exports__,"a",(function(){return AddressForm_AddressForm})),__webpack_require__.d(__webpack_exports__,"b",(function(){return AddressView_AddressView})),__webpack_require__.d(__webpack_exports__,"m",(function(){return ContactInfoForm_getContactInfoSchema})),__webpack_require__.d(__webpack_exports__,"d",(function(){return ContactInfoForm_ContactInfoForm})),__webpack_require__.d(__webpack_exports__,"c",(function(){return Checkbox})),__webpack_require__.d(__webpack_exports__,"e",(function(){return LimitedTextField})),__webpack_require__.d(__webpack_exports__,"k",(function(){return TextField})),__webpack_require__.d(__webpack_exports__,"f",(function(){return Loading_Loading})),__webpack_require__.d(__webpack_exports__,"i",(function(){return ShippingMethodText_ShippingMethodText})),__webpack_require__.d(__webpack_exports__,"n",(function(){return PaymentForm_getPaymentSchema})),__webpack_require__.d(__webpack_exports__,"g",(function(){return PaymentForm_PaymentForm})),__webpack_require__.d(__webpack_exports__,"h",(function(){return PaymentView_PaymentView})),__webpack_require__.d(__webpack_exports__,"o",(function(){return shippingOptionsSchema})),__webpack_require__.d(__webpack_exports__,"j",(function(){return ShippingOptionsForm_ShippingOptionsForm}));var jsx_runtime=__webpack_require__(1),react=__webpack_require__(0),react_default=__webpack_require__.n(react),index_esm=__webpack_require__(33),useTranslation=__webpack_require__(1149),es=__webpack_require__(14),objectSpread2=__webpack_require__(30),ErrorMessage_ErrorMessage=function ErrorMessage(_ref){var error=_ref.error,t=Object(useTranslation.a)().t;if(void 0===error)return null;if("string"==typeof error)return Object(jsx_runtime.jsx)("div",{className:"error-text",children:error});var key=error.key,values=error.values;return Object(jsx_runtime.jsx)("div",{className:"error-text",children:t(key,values)})};try{ErrorMessage_ErrorMessage.displayName="ErrorMessage",ErrorMessage_ErrorMessage.__docgenInfo={description:"",displayName:"ErrorMessage",props:{error:{defaultValue:null,description:"",name:"error",required:!1,type:{name:"string | ValidationError"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/Form/ErrorMessage.tsx#ErrorMessage"]={docgenInfo:ErrorMessage_ErrorMessage.__docgenInfo,name:"ErrorMessage",path:"src/components/Form/ErrorMessage.tsx#ErrorMessage"})}catch(__react_docgen_typescript_loader_error){}var Checkbox=react_default.a.forwardRef((function(_ref,ref){var id=_ref.id,name=_ref.name,label=_ref.label,error=_ref.error,_ref$renderContainer=_ref.renderContainer,renderContainer=void 0===_ref$renderContainer?function(props){return Object(jsx_runtime.jsx)("input",Object(objectSpread2.a)({},props))}:_ref$renderContainer,onBlur=_ref.onBlur,onChange=_ref.onChange;return Object(jsx_runtime.jsxs)("div",{className:"form-check form-check-inline",children:[renderContainer({id:id,name:name,type:"checkbox",ref:ref,className:"form-check-input",onBlur:onBlur,onChange:onChange}),void 0!==label?Object(jsx_runtime.jsx)("label",{className:"form-check-label",htmlFor:id,children:label}):null,Object(jsx_runtime.jsx)(ErrorMessage_ErrorMessage,{error:error})]})}));try{Checkbox.displayName="Checkbox",Checkbox.__docgenInfo={description:'Uses the "Render Prop" pattern to pass through arbitrary props that it\ndoesn\'t understand.\nSee https://blog.andrewbran.ch/polymorphic-react-components/',displayName:"Checkbox",props:{id:{defaultValue:null,description:"used to make label and errorText accessible for screen readers",name:"id",required:!1,type:{name:"string"}},name:{defaultValue:null,description:"passed directly to the input element",name:"name",required:!1,type:{name:"string"}},label:{defaultValue:null,description:"the label content",name:"label",required:!1,type:{name:"ReactNode"}},error:{defaultValue:null,description:"error text",name:"error",required:!1,type:{name:"string | ValidationError"}},renderContainer:{defaultValue:{value:"(props) => "},description:"",name:"renderContainer",required:!1,type:{name:"((props: InputInjectedProps) => Element)"}},onBlur:{defaultValue:null,description:"",name:"onBlur",required:!1,type:{name:"((e: FocusEvent) => void)"}},onChange:{defaultValue:null,description:"",name:"onChange",required:!1,type:{name:"((e: ChangeEvent) => void)"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/Form/Checkbox.tsx#Checkbox"]={docgenInfo:Checkbox.__docgenInfo,name:"Checkbox",path:"src/components/Form/Checkbox.tsx#Checkbox"})}catch(__react_docgen_typescript_loader_error){}var slicedToArray=__webpack_require__(80),LimitedTextField=react_default.a.forwardRef((function(_ref,ref){var id=_ref.id,name=_ref.name,label=_ref.label,maxCount=_ref.maxCount,error=_ref.error,_ref$renderContainer=_ref.renderContainer,renderContainer=void 0===_ref$renderContainer?function(props){return Object(jsx_runtime.jsx)("input",Object(objectSpread2.a)({},props))}:_ref$renderContainer,onBlur=_ref.onBlur,onChange=_ref.onChange,t=Object(useTranslation.a)().t,_useState=Object(react.useState)(""),_useState2=Object(slicedToArray.a)(_useState,2),value=_useState2[0],setValue=_useState2[1],remainingCount=maxCount-value.length;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[void 0!==label?Object(jsx_runtime.jsx)("label",{htmlFor:id,children:label}):null,renderContainer({id:id,name:name,type:"text",ref:ref,className:"form-control form-control-sm",onBlur:onBlur,onChange:function handleChange(e){setValue(e.currentTarget.value),void 0!==onChange&&onChange(e)}}),Object(jsx_runtime.jsxs)("div",{className:remainingCount<0?"text-danger":"",children:[remainingCount," ",t("text.characters")]}),Object(jsx_runtime.jsx)(ErrorMessage_ErrorMessage,{error:error})]})}));try{LimitedTextField.displayName="LimitedTextField",LimitedTextField.__docgenInfo={description:'Uses the "Render Prop" pattern to pass through arbitrary props that it\ndoesn\'t understand.\nSee https://blog.andrewbran.ch/polymorphic-react-components/',displayName:"LimitedTextField",props:{id:{defaultValue:null,description:"used to make label and errorText accessible for screen readers",name:"id",required:!1,type:{name:"string"}},name:{defaultValue:null,description:"passed directly to the input element",name:"name",required:!1,type:{name:"string"}},label:{defaultValue:null,description:"the label content",name:"label",required:!1,type:{name:"ReactNode"}},maxCount:{defaultValue:null,description:"maximum count of characters allowed in text field",name:"maxCount",required:!0,type:{name:"number"}},error:{defaultValue:null,description:"error text",name:"error",required:!1,type:{name:"string | ValidationError"}},renderContainer:{defaultValue:{value:"(props) => "},description:"",name:"renderContainer",required:!1,type:{name:"((props: InputInjectedProps) => Element)"}},onBlur:{defaultValue:null,description:"",name:"onBlur",required:!1,type:{name:"((e: FocusEvent) => void)"}},onChange:{defaultValue:null,description:"",name:"onChange",required:!1,type:{name:"((e: ChangeEvent) => void)"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/Form/LimitedTextField.tsx#LimitedTextField"]={docgenInfo:LimitedTextField.__docgenInfo,name:"LimitedTextField",path:"src/components/Form/LimitedTextField.tsx#LimitedTextField"})}catch(__react_docgen_typescript_loader_error){}var Radio=react_default.a.forwardRef((function(_ref,ref){var id=_ref.id,value=_ref.value,name=_ref.name,label=_ref.label,error=_ref.error,_ref$renderContainer=_ref.renderContainer,renderContainer=void 0===_ref$renderContainer?function(props){return Object(jsx_runtime.jsx)("input",Object(objectSpread2.a)({},props))}:_ref$renderContainer,onBlur=_ref.onBlur,onChange=_ref.onChange;return Object(jsx_runtime.jsxs)("div",{className:"form-check form-check-inline",children:[renderContainer({id:id,value:value,name:name,type:"radio",ref:ref,className:"form-check-input",onBlur:onBlur,onChange:onChange}),void 0!==label?Object(jsx_runtime.jsx)("label",{className:"form-check-label",htmlFor:id,children:label}):null,Object(jsx_runtime.jsx)(ErrorMessage_ErrorMessage,{error:error})]})}));try{Radio.displayName="Radio",Radio.__docgenInfo={description:'Uses the "Render Prop" pattern to pass through arbitrary props that it\ndoesn\'t understand.\nSee https://blog.andrewbran.ch/polymorphic-react-components/',displayName:"Radio",props:{id:{defaultValue:null,description:"used to make label and errorText accessible for screen readers",name:"id",required:!1,type:{name:"string"}},name:{defaultValue:null,description:"passed directly to the input element",name:"name",required:!1,type:{name:"string"}},label:{defaultValue:null,description:"the label content",name:"label",required:!1,type:{name:"ReactNode"}},error:{defaultValue:null,description:"error text",name:"error",required:!1,type:{name:"string | ValidationError"}},renderContainer:{defaultValue:{value:"(props) => "},description:"",name:"renderContainer",required:!1,type:{name:"((props: InputInjectedProps) => Element)"}},onBlur:{defaultValue:null,description:"",name:"onBlur",required:!1,type:{name:"((e: FocusEvent) => void)"}},onChange:{defaultValue:null,description:"",name:"onChange",required:!1,type:{name:"((e: ChangeEvent) => void)"}},value:{defaultValue:null,description:"used to make label and errorText accessible for screen readers",name:"value",required:!1,type:{name:"string"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/Form/Radio.tsx#Radio"]={docgenInfo:Radio.__docgenInfo,name:"Radio",path:"src/components/Form/Radio.tsx#Radio"})}catch(__react_docgen_typescript_loader_error){}var TextField=react_default.a.forwardRef((function(_ref,ref){var id=_ref.id,name=_ref.name,label=_ref.label,error=_ref.error,_ref$renderContainer=_ref.renderContainer,renderContainer=void 0===_ref$renderContainer?function(props){return Object(jsx_runtime.jsx)("input",Object(objectSpread2.a)({},props))}:_ref$renderContainer,onBlur=_ref.onBlur,onChange=_ref.onChange;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[void 0!==label?Object(jsx_runtime.jsx)("label",{htmlFor:id,children:label}):null,renderContainer({id:id,name:name,type:"text",ref:ref,className:"form-control form-control-sm",onBlur:onBlur,onChange:onChange}),Object(jsx_runtime.jsx)(ErrorMessage_ErrorMessage,{error:error})]})}));try{TextField.displayName="TextField",TextField.__docgenInfo={description:'Uses the "Render Prop" pattern to pass through arbitrary props that it\ndoesn\'t understand.\nSee https://blog.andrewbran.ch/polymorphic-react-components/',displayName:"TextField",props:{id:{defaultValue:null,description:"used to make label and errorText accessible for screen readers",name:"id",required:!1,type:{name:"string"}},name:{defaultValue:null,description:"passed directly to the input element",name:"name",required:!1,type:{name:"string"}},label:{defaultValue:null,description:"the label content",name:"label",required:!1,type:{name:"ReactNode"}},error:{defaultValue:null,description:"error text",name:"error",required:!1,type:{name:"string | ValidationError"}},renderContainer:{defaultValue:{value:"(props) => "},description:"",name:"renderContainer",required:!1,type:{name:"((props: InputInjectedProps) => Element)"}},onBlur:{defaultValue:null,description:"",name:"onBlur",required:!1,type:{name:"((e: FocusEvent) => void)"}},onChange:{defaultValue:null,description:"",name:"onChange",required:!1,type:{name:"((e: ChangeEvent) => void)"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/Form/TextField.tsx#TextField"]={docgenInfo:TextField.__docgenInfo,name:"TextField",path:"src/components/Form/TextField.tsx#TextField"})}catch(__react_docgen_typescript_loader_error){}var AddressForm_getAddressSchema=function getAddressSchema(){return es.e().shape({firstName:es.g().required().min(2),lastName:es.g().required().min(2),company:es.g(),address:es.g().required(),city:es.g().required(),state:es.g().required(),zip:es.g().required()})},AddressForm_AddressForm=function AddressForm(_ref){var _errors$parentName,_errors$parentName$fi,_errors$parentName2,_errors$parentName2$l,_errors$parentName3,_errors$parentName3$c,_errors$parentName4,_errors$parentName4$a,_errors$parentName5,_errors$parentName5$c,_errors$parentName6,_errors$parentName6$s,_errors$parentName7,_errors$parentName7$z,title=_ref.title,parentName=_ref.parentName,t=Object(useTranslation.a)().t,_useFormContext=Object(index_esm.useFormContext)(),errors=_useFormContext.errors,register=_useFormContext.register;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[void 0!==title?Object(jsx_runtime.jsx)("h5",{className:"mb-3",children:title}):null,Object(jsx_runtime.jsxs)("div",{className:"row",children:[Object(jsx_runtime.jsx)("div",{className:"col-md-6 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"firstName",name:"".concat(parentName,".firstName"),label:t("text.firstName"),ref:register,error:null===(_errors$parentName=errors[parentName])||void 0===_errors$parentName||null===(_errors$parentName$fi=_errors$parentName.firstName)||void 0===_errors$parentName$fi?void 0:_errors$parentName$fi.message})}),Object(jsx_runtime.jsx)("div",{className:"col-md-6 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"lastName",name:"".concat(parentName,".lastName"),label:t("text.lastName"),ref:register,error:null===(_errors$parentName2=errors[parentName])||void 0===_errors$parentName2||null===(_errors$parentName2$l=_errors$parentName2.lastName)||void 0===_errors$parentName2$l?void 0:_errors$parentName2$l.message})})]}),Object(jsx_runtime.jsx)("div",{className:"mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"company",name:"".concat(parentName,".company"),label:t("text.companyOptional"),ref:register,error:null===(_errors$parentName3=errors[parentName])||void 0===_errors$parentName3||null===(_errors$parentName3$c=_errors$parentName3.company)||void 0===_errors$parentName3$c?void 0:_errors$parentName3$c.message})}),Object(jsx_runtime.jsx)("div",{className:"mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"address",name:"".concat(parentName,".address"),label:t("text.address"),ref:register,error:null===(_errors$parentName4=errors[parentName])||void 0===_errors$parentName4||null===(_errors$parentName4$a=_errors$parentName4.address)||void 0===_errors$parentName4$a?void 0:_errors$parentName4$a.message})}),Object(jsx_runtime.jsxs)("div",{className:"row",children:[Object(jsx_runtime.jsx)("div",{className:"col-md-5 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"city",name:"".concat(parentName,".city"),label:t("text.city"),ref:register,error:null===(_errors$parentName5=errors[parentName])||void 0===_errors$parentName5||null===(_errors$parentName5$c=_errors$parentName5.city)||void 0===_errors$parentName5$c?void 0:_errors$parentName5$c.message})}),Object(jsx_runtime.jsx)("div",{className:"col-md-4 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"state",name:"".concat(parentName,".state"),label:t("text.state"),ref:register,error:null===(_errors$parentName6=errors[parentName])||void 0===_errors$parentName6||null===(_errors$parentName6$s=_errors$parentName6.state)||void 0===_errors$parentName6$s?void 0:_errors$parentName6$s.message})}),Object(jsx_runtime.jsx)("div",{className:"col-md-3 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"zip",name:"".concat(parentName,".zip"),label:t("text.zip"),ref:register,error:null===(_errors$parentName7=errors[parentName])||void 0===_errors$parentName7||null===(_errors$parentName7$z=_errors$parentName7.zip)||void 0===_errors$parentName7$z?void 0:_errors$parentName7$z.message})})]})]})};try{AddressForm_AddressForm.displayName="AddressForm",AddressForm_AddressForm.__docgenInfo={description:"",displayName:"AddressForm",props:{title:{defaultValue:null,description:"",name:"title",required:!1,type:{name:"string"}},parentName:{defaultValue:null,description:'parent name e.g. "shippingAddress"',name:"parentName",required:!0,type:{name:"string"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/AddressForm/AddressForm.tsx#AddressForm"]={docgenInfo:AddressForm_AddressForm.__docgenInfo,name:"AddressForm",path:"src/components/AddressForm/AddressForm.tsx#AddressForm"})}catch(__react_docgen_typescript_loader_error){}var utils_esm=__webpack_require__(113),isBlank=utils_esm.a.isBlank,AddressView_AddressView=function AddressView(_ref){var label=_ref.label,address=_ref.address,firstName=address.firstName,lastName=address.lastName,company=address.company,addressLine=address.address,city=address.city,state=address.state,zip=address.zip;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[void 0!==label?Object(jsx_runtime.jsx)("h6",{className:"mb-0",children:label}):null,Object(jsx_runtime.jsxs)("p",{children:[firstName," ",lastName,isBlank(company)?null:Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)("br",{}),company]}),Object(jsx_runtime.jsx)("br",{}),addressLine,Object(jsx_runtime.jsx)("br",{}),city,", ",state," ",zip]})]})};try{AddressView_AddressView.displayName="AddressView",AddressView_AddressView.__docgenInfo={description:"",displayName:"AddressView",props:{label:{defaultValue:null,description:"",name:"label",required:!1,type:{name:"string"}},address:{defaultValue:null,description:"",name:"address",required:!0,type:{name:"Address"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/AddressView/AddressView.tsx#AddressView"]={docgenInfo:AddressView_AddressView.__docgenInfo,name:"AddressView",path:"src/components/AddressView/AddressView.tsx#AddressView"})}catch(__react_docgen_typescript_loader_error){}var ContactInfoForm_getContactInfoSchema=function getContactInfoSchema(){return es.e().shape({email:es.g().email().required()})},ContactInfoForm_ContactInfoForm=function ContactInfoForm(){var _errors$contactInfo,_errors$contactInfo$e,t=Object(useTranslation.a)().t,_useFormContext=Object(index_esm.useFormContext)(),errors=_useFormContext.errors,register=_useFormContext.register;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)("h5",{className:"mb-3",children:t("text.contactInfo")}),Object(jsx_runtime.jsx)("div",{className:"mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"email",name:"contactInfo.email",label:t("text.email"),ref:register,error:null===(_errors$contactInfo=errors.contactInfo)||void 0===_errors$contactInfo||null===(_errors$contactInfo$e=_errors$contactInfo.email)||void 0===_errors$contactInfo$e?void 0:_errors$contactInfo$e.message})})]})},Loading_Loading=(__webpack_require__(513),function Loading(){return Object(jsx_runtime.jsx)("div",{className:"d-flex justify-content-center",children:Object(jsx_runtime.jsx)("div",{className:"spinner-border",role:"status",children:Object(jsx_runtime.jsx)("span",{className:"sr-only",children:"Loading..."})})})}),PaymentTypeText_PaymentTypeText=function PaymentTypeText(_ref){var paymentType=_ref.paymentType,t=Object(useTranslation.a)().t,PaymentTypeNames={creditCard:t("text.creditCard"),bankAccount:t("text.bankAccount")};return Object(jsx_runtime.jsx)(react.Fragment,{children:PaymentTypeNames[paymentType]})};try{PaymentTypeText_PaymentTypeText.displayName="PaymentTypeText",PaymentTypeText_PaymentTypeText.__docgenInfo={description:"",displayName:"PaymentTypeText",props:{paymentType:{defaultValue:null,description:"",name:"paymentType",required:!0,type:{name:"enum",value:[{value:'"creditCard"'},{value:'"bankAccount"'}]}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/PaymentView/PaymentTypeText.tsx#PaymentTypeText"]={docgenInfo:PaymentTypeText_PaymentTypeText.__docgenInfo,name:"PaymentTypeText",path:"src/components/PaymentView/PaymentTypeText.tsx#PaymentTypeText"})}catch(__react_docgen_typescript_loader_error){}var PaymentView_isBlank=utils_esm.a.isBlank,PaymentView_PaymentView=function PaymentView(_ref){var paymentMethod=_ref.paymentMethod,t=Object(useTranslation.a)().t;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)("h6",{className:"mb-0",children:t("text.paymentMethod")}),Object(jsx_runtime.jsxs)("p",{children:[Object(jsx_runtime.jsx)(PaymentTypeText_PaymentTypeText,{paymentType:paymentMethod.type}),Object(jsx_runtime.jsx)("br",{}),"creditCard"!==paymentMethod.type||PaymentView_isBlank(paymentMethod.nameOnCard)?null:Object(jsx_runtime.jsxs)(react.Fragment,{children:[paymentMethod.nameOnCard,Object(jsx_runtime.jsx)("br",{}),t("text.cardNumber"),": ",paymentMethod.cardNumber,Object(jsx_runtime.jsx)("br",{}),t("text.expiration"),": ",paymentMethod.expiration,Object(jsx_runtime.jsx)("br",{}),t("text.cvv"),": ",paymentMethod.cvv]}),"bankAccount"!==paymentMethod.type||PaymentView_isBlank(paymentMethod.accountHolderName)?null:Object(jsx_runtime.jsxs)(react.Fragment,{children:[paymentMethod.accountHolderName,Object(jsx_runtime.jsx)("br",{}),paymentMethod.bankName,Object(jsx_runtime.jsx)("br",{}),t("text.routingNumber"),": ",paymentMethod.routingNumber,Object(jsx_runtime.jsx)("br",{}),t("text.accountNumber"),": ",paymentMethod.accountNumber]})]})]})};try{PaymentView_PaymentView.displayName="PaymentView",PaymentView_PaymentView.__docgenInfo={description:"",displayName:"PaymentView",props:{paymentMethod:{defaultValue:null,description:"",name:"paymentMethod",required:!0,type:{name:"PaymentMethod"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/PaymentView/PaymentView.tsx#PaymentView"]={docgenInfo:PaymentView_PaymentView.__docgenInfo,name:"PaymentView",path:"src/components/PaymentView/PaymentView.tsx#PaymentView"})}catch(__react_docgen_typescript_loader_error){}var ShippingMethodText_ShippingMethodText=function ShippingMethodText(_ref){var shippingMethod=_ref.shippingMethod,t=Object(useTranslation.a)().t,ShippingMethodNames={ground:t("text.ground"),secondDay:t("text.secondDay"),overnight:t("text.overnight")};return Object(jsx_runtime.jsx)(react.Fragment,{children:ShippingMethodNames[shippingMethod]})};try{ShippingMethodText_ShippingMethodText.displayName="ShippingMethodText",ShippingMethodText_ShippingMethodText.__docgenInfo={description:"",displayName:"ShippingMethodText",props:{shippingMethod:{defaultValue:null,description:"",name:"shippingMethod",required:!0,type:{name:"enum",value:[{value:'"ground"'},{value:'"secondDay"'},{value:'"overnight"'}]}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/OrderDetail/ShippingMethodText.tsx#ShippingMethodText"]={docgenInfo:ShippingMethodText_ShippingMethodText.__docgenInfo,name:"ShippingMethodText",path:"src/components/OrderDetail/ShippingMethodText.tsx#ShippingMethodText"})}catch(__react_docgen_typescript_loader_error){}var OrderDetail_isBlank=utils_esm.a.isBlank,OrderDetail_OrderDetail=function OrderDetail(_ref){var order=_ref.order,t=Object(useTranslation.a)().t,contactInfo=order.contactInfo,shippingAddress=order.shippingAddress,shippingOptions=order.shippingOptions,paymentMethod=order.paymentMethod;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)("h4",{className:"text-muted",children:t("text.orderDetail")}),Object(jsx_runtime.jsxs)("div",{className:"border p-3",children:[Object(jsx_runtime.jsx)("h6",{className:"mb-0",children:t("text.contactInfo")}),Object(jsx_runtime.jsxs)("p",{children:["Email: ",contactInfo.email]}),OrderDetail_isBlank(shippingAddress.firstName)?null:Object(jsx_runtime.jsx)(AddressView_AddressView,{label:t("text.shippingAddress"),address:shippingAddress}),Object(jsx_runtime.jsx)("h6",{className:"mb-0",children:t("text.shippingOptions")}),Object(jsx_runtime.jsxs)("p",{children:[t("text.shippingMethod"),":"," ",Object(jsx_runtime.jsx)(ShippingMethodText_ShippingMethodText,{shippingMethod:shippingOptions.shippingMethod}),Object(jsx_runtime.jsx)("br",{}),t("text.giftWrapping"),":"," ",shippingOptions.giftWrapping?t("text.yes"):t("text.no")]}),Object(jsx_runtime.jsx)(PaymentView_PaymentView,{paymentMethod:paymentMethod})]})]})};try{OrderDetail_OrderDetail.displayName="OrderDetail",OrderDetail_OrderDetail.__docgenInfo={description:"",displayName:"OrderDetail",props:{order:{defaultValue:null,description:"",name:"order",required:!0,type:{name:"Order"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/OrderDetail/OrderDetail.tsx#OrderDetail"]={docgenInfo:OrderDetail_OrderDetail.__docgenInfo,name:"OrderDetail",path:"src/components/OrderDetail/OrderDetail.tsx#OrderDetail"})}catch(__react_docgen_typescript_loader_error){}var dist=__webpack_require__(172),models=__webpack_require__(141),OrderSummary_OrderSummary=function OrderSummary(_ref){var order=_ref.order,t=Object(useTranslation.a)().t,orderItems=order.orderItems,_Order$getOrderTotal=models.Order.getOrderTotal(order),orderItemsTotal=_Order$getOrderTotal.orderItemsTotal,shippingCharges=_Order$getOrderTotal.shippingCharges,orderTotal=_Order$getOrderTotal.orderTotal,orderItemsTotalStr=dist.NumberUtils.formatAsMoney(orderItemsTotal),shippingChargesStr=dist.NumberUtils.formatAsMoney(shippingCharges),orderTotalStr=dist.NumberUtils.formatAsMoney(orderTotal);return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsxs)("h4",{className:"d-flex justify-content-between align-items-center mb-3",children:[Object(jsx_runtime.jsx)("span",{className:"text-muted",children:t("text.orderSummary")}),Object(jsx_runtime.jsx)("span",{className:"badge badge-secondary badge-pill",children:orderItems.length})]}),Object(jsx_runtime.jsxs)("ul",{className:"list-group mb-3",children:[orderItems.map((function(orderItem){return Object(jsx_runtime.jsxs)("li",{className:"list-group-item d-flex justify-content-between lh-condensed",children:[Object(jsx_runtime.jsxs)("div",{children:[Object(jsx_runtime.jsx)("h6",{className:"my-0",children:orderItem.item.name}),Object(jsx_runtime.jsxs)("small",{className:"text-muted",children:[t("text.quantity"),": ",orderItem.qty]})]}),Object(jsx_runtime.jsxs)("span",{className:"text-muted",children:["$",dist.NumberUtils.formatAsMoney(models.OrderItem.getTotal(orderItem))]})]},orderItem.item.id)})),Object(jsx_runtime.jsxs)("li",{className:"list-group-item",children:[Object(jsx_runtime.jsxs)("div",{className:"d-flex justify-content-between",children:[Object(jsx_runtime.jsx)("span",{children:t("text.items")}),Object(jsx_runtime.jsxs)("strong",{children:["$",orderItemsTotalStr]})]}),Object(jsx_runtime.jsxs)("div",{className:"d-flex justify-content-between",children:[Object(jsx_runtime.jsx)("span",{children:t("text.shippingHandling")}),Object(jsx_runtime.jsxs)("strong",{children:["$",shippingChargesStr]})]})]}),Object(jsx_runtime.jsxs)("li",{className:"list-group-item d-flex justify-content-between text-primary",children:[Object(jsx_runtime.jsx)("span",{children:t("text.orderTotal")}),Object(jsx_runtime.jsxs)("strong",{children:["$",orderTotalStr]})]})]})]})};try{OrderSummary_OrderSummary.displayName="OrderSummary",OrderSummary_OrderSummary.__docgenInfo={description:"",displayName:"OrderSummary",props:{order:{defaultValue:null,description:"",name:"order",required:!0,type:{name:"Order"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/OrderSummary/OrderSummary.tsx#OrderSummary"]={docgenInfo:OrderSummary_OrderSummary.__docgenInfo,name:"OrderSummary",path:"src/components/OrderSummary/OrderSummary.tsx#OrderSummary"})}catch(__react_docgen_typescript_loader_error){}var BankAccountForm_BankAccountForm=function BankAccountForm(){var _errors$paymentMethod,_errors$paymentMethod2,_errors$paymentMethod3,_errors$paymentMethod4,_errors$paymentMethod5,_errors$paymentMethod6,_errors$paymentMethod7,_errors$paymentMethod8,t=Object(useTranslation.a)().t,_useFormContext=Object(index_esm.useFormContext)(),errors=_useFormContext.errors,register=_useFormContext.register;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)("div",{className:"mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"accountHolderName",name:"paymentMethod.accountHolderName",label:t("text.accountHolderName"),ref:register,error:null===(_errors$paymentMethod=errors.paymentMethod)||void 0===_errors$paymentMethod||null===(_errors$paymentMethod2=_errors$paymentMethod.accountHolderName)||void 0===_errors$paymentMethod2?void 0:_errors$paymentMethod2.message})}),Object(jsx_runtime.jsx)("div",{className:"mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"bankName",name:"paymentMethod.bankName",label:t("text.bankName"),ref:register,error:null===(_errors$paymentMethod3=errors.paymentMethod)||void 0===_errors$paymentMethod3||null===(_errors$paymentMethod4=_errors$paymentMethod3.bankName)||void 0===_errors$paymentMethod4?void 0:_errors$paymentMethod4.message})}),Object(jsx_runtime.jsxs)("div",{className:"row",children:[Object(jsx_runtime.jsx)("div",{className:"col-md-6 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"routingNumber",name:"paymentMethod.routingNumber",label:t("text.routingNumber"),ref:register,error:null===(_errors$paymentMethod5=errors.paymentMethod)||void 0===_errors$paymentMethod5||null===(_errors$paymentMethod6=_errors$paymentMethod5.routingNumber)||void 0===_errors$paymentMethod6?void 0:_errors$paymentMethod6.message})}),Object(jsx_runtime.jsx)("div",{className:"col-md-6 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"accountNumber",name:"paymentMethod.accountNumber",label:t("text.accountNumber"),ref:register,error:null===(_errors$paymentMethod7=errors.paymentMethod)||void 0===_errors$paymentMethod7||null===(_errors$paymentMethod8=_errors$paymentMethod7.accountNumber)||void 0===_errors$paymentMethod8?void 0:_errors$paymentMethod8.message})})]})]})},CreditCardForm_CreditCardForm=function CreditCardForm(){var _errors$paymentMethod,_errors$paymentMethod2,_errors$paymentMethod3,_errors$paymentMethod4,_errors$paymentMethod5,_errors$paymentMethod6,_errors$paymentMethod7,_errors$paymentMethod8,t=Object(useTranslation.a)().t,_useFormContext=Object(index_esm.useFormContext)(),errors=_useFormContext.errors,register=_useFormContext.register;return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsxs)("div",{className:"row",children:[Object(jsx_runtime.jsx)("div",{className:"col-md-6 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"nameOnCard",name:"paymentMethod.nameOnCard",label:t("text.nameOnCard"),ref:register,error:null===(_errors$paymentMethod=errors.paymentMethod)||void 0===_errors$paymentMethod||null===(_errors$paymentMethod2=_errors$paymentMethod.nameOnCard)||void 0===_errors$paymentMethod2?void 0:_errors$paymentMethod2.message})}),Object(jsx_runtime.jsx)("div",{className:"col-md-6 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"cardNumber",name:"paymentMethod.cardNumber",label:t("text.creditCardNumber"),ref:register,error:null===(_errors$paymentMethod3=errors.paymentMethod)||void 0===_errors$paymentMethod3||null===(_errors$paymentMethod4=_errors$paymentMethod3.cardNumber)||void 0===_errors$paymentMethod4?void 0:_errors$paymentMethod4.message})})]}),Object(jsx_runtime.jsxs)("div",{className:"row",children:[Object(jsx_runtime.jsx)("div",{className:"col-md-3 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"expiration",name:"paymentMethod.expiration",label:t("text.expiration"),ref:register,error:null===(_errors$paymentMethod5=errors.paymentMethod)||void 0===_errors$paymentMethod5||null===(_errors$paymentMethod6=_errors$paymentMethod5.expiration)||void 0===_errors$paymentMethod6?void 0:_errors$paymentMethod6.message})}),Object(jsx_runtime.jsx)("div",{className:"col-md-3 mb-3",children:Object(jsx_runtime.jsx)(TextField,{id:"cvv",name:"paymentMethod.cvv",label:t("text.cvv"),ref:register,error:null===(_errors$paymentMethod7=errors.paymentMethod)||void 0===_errors$paymentMethod7||null===(_errors$paymentMethod8=_errors$paymentMethod7.cvv)||void 0===_errors$paymentMethod8?void 0:_errors$paymentMethod8.message})})]})]})},PaymentForm_getPaymentSchema=function getPaymentSchema(){return es.b((function(value){return void 0===value?es.c().notRequired():"creditCard"===value.type?function getCreditCardSchema(){return es.e().shape({nameOnCard:es.g().required(),cardNumber:es.g().required(),expiration:es.g().required(),cvv:es.d().required()})}():function getBankAccountSchema(){return es.e().shape({accountHolderName:es.g().required(),bankName:es.g().required(),routingNumber:es.g().required(),accountNumber:es.g().required()})}()}))},PaymentForm_PaymentForm=function PaymentForm(){var _errors$paymentMethod,_errors$paymentMethod2,_errors$paymentMethod3,_errors$paymentMethod4,t=Object(useTranslation.a)().t,_useFormContext=Object(index_esm.useFormContext)(),errors=_useFormContext.errors,register=_useFormContext.register,paymentType=(0,_useFormContext.watch)("paymentMethod.type");return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)("h5",{className:"mb-3",children:t("text.paymentMethod")}),Object(jsx_runtime.jsx)(Radio,{id:"creditCard",value:"creditCard",name:"paymentMethod.type",label:t("text.creditCard"),ref:register,error:null===(_errors$paymentMethod=errors.paymentMethod)||void 0===_errors$paymentMethod||null===(_errors$paymentMethod2=_errors$paymentMethod.type)||void 0===_errors$paymentMethod2?void 0:_errors$paymentMethod2.message}),Object(jsx_runtime.jsx)(Radio,{id:"bankAccount",value:"bankAccount",name:"paymentMethod.type",label:t("text.bankAccount"),ref:register,error:null===(_errors$paymentMethod3=errors.paymentMethod)||void 0===_errors$paymentMethod3||null===(_errors$paymentMethod4=_errors$paymentMethod3.type)||void 0===_errors$paymentMethod4?void 0:_errors$paymentMethod4.message}),"creditCard"===paymentType?Object(jsx_runtime.jsx)(CreditCardForm_CreditCardForm,{}):Object(jsx_runtime.jsx)(BankAccountForm_BankAccountForm,{})]})},shippingOptionsSchema=es.e().shape({shippingMethod:es.g().required(),giftWrapping:es.a().required()}),ShippingOptionsForm_ShippingOptionsForm=function ShippingOptionsForm(_ref){var _errors$shippingOptio,_errors$shippingOptio2,_errors$shippingOptio3,_errors$shippingOptio4,_errors$shippingOptio5,_errors$shippingOptio6,_errors$shippingOptio7,_errors$shippingOptio8,onShippingMethodChanged=_ref.onShippingMethodChanged,t=Object(useTranslation.a)().t,_useFormContext=Object(index_esm.useFormContext)(),errors=_useFormContext.errors,register=_useFormContext.register,handleShippingMethodChanged=function handleShippingMethodChanged(event){onShippingMethodChanged(event.target.value)};return Object(jsx_runtime.jsxs)(react.Fragment,{children:[Object(jsx_runtime.jsx)("h5",{className:"mb-3",children:t("text.shippingOptions")}),Object(jsx_runtime.jsxs)("div",{className:"d-block my-3",children:[Object(jsx_runtime.jsx)(Radio,{id:"ground",value:"ground",name:"shippingOptions.shippingMethod",label:t("text.groundLong"),ref:register,error:null===(_errors$shippingOptio=errors.shippingOptions)||void 0===_errors$shippingOptio||null===(_errors$shippingOptio2=_errors$shippingOptio.shippingMethod)||void 0===_errors$shippingOptio2?void 0:_errors$shippingOptio2.message,onChange:handleShippingMethodChanged}),Object(jsx_runtime.jsx)(Radio,{id:"secondDay",value:"secondDay",name:"shippingOptions.shippingMethod",label:t("text.secondDay"),ref:register,error:null===(_errors$shippingOptio3=errors.shippingOptions)||void 0===_errors$shippingOptio3||null===(_errors$shippingOptio4=_errors$shippingOptio3.shippingMethod)||void 0===_errors$shippingOptio4?void 0:_errors$shippingOptio4.message,onChange:handleShippingMethodChanged}),Object(jsx_runtime.jsx)(Radio,{id:"overnight",value:"overnight",name:"shippingOptions.shippingMethod",label:t("text.overnight"),ref:register,error:null===(_errors$shippingOptio5=errors.shippingOptions)||void 0===_errors$shippingOptio5||null===(_errors$shippingOptio6=_errors$shippingOptio5.shippingMethod)||void 0===_errors$shippingOptio6?void 0:_errors$shippingOptio6.message,onChange:handleShippingMethodChanged})]}),Object(jsx_runtime.jsx)(Checkbox,{id:"giftWrapping",name:"shippingOptions.giftWrapping",label:t("text.giftWrapping"),ref:register,error:null===(_errors$shippingOptio7=errors.shippingOptions)||void 0===_errors$shippingOptio7||null===(_errors$shippingOptio8=_errors$shippingOptio7.giftWrapping)||void 0===_errors$shippingOptio8?void 0:_errors$shippingOptio8.message})]})};try{ShippingOptionsForm_ShippingOptionsForm.displayName="ShippingOptionsForm",ShippingOptionsForm_ShippingOptionsForm.__docgenInfo={description:"",displayName:"ShippingOptionsForm",props:{onShippingMethodChanged:{defaultValue:null,description:"",name:"onShippingMethodChanged",required:!0,type:{name:"(shippingMethod: ShippingMethod) => void"}}}},"undefined"!=typeof STORYBOOK_REACT_CLASSES&&(STORYBOOK_REACT_CLASSES["src/components/ShippingOptionsForm/ShippingOptionsForm.tsx#ShippingOptionsForm"]={docgenInfo:ShippingOptionsForm_ShippingOptionsForm.__docgenInfo,name:"ShippingOptionsForm",path:"src/components/ShippingOptionsForm/ShippingOptionsForm.tsx#ShippingOptionsForm"})}catch(__react_docgen_typescript_loader_error){}},491:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.d(__webpack_exports__,"a",(function(){return newAddress}));var newAddress=function newAddress(){return{firstName:"",lastName:"",company:"",address:"",city:"",state:"",zip:""}}},492:function(module,exports){},493:function(module,exports){},494:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.d(__webpack_exports__,"a",(function(){return Order}));var _OrderItem__WEBPACK_IMPORTED_MODULE_0__=__webpack_require__(225),_ShippingOptions__WEBPACK_IMPORTED_MODULE_1__=__webpack_require__(226),Order={getOrderItemsTotal:function getOrderItemsTotal(order){return order.orderItems.reduce((function(total,orderItem){return total+_OrderItem__WEBPACK_IMPORTED_MODULE_0__.a.getTotal(orderItem)}),0)},getShippingCharges:function getShippingCharges(order){return _ShippingOptions__WEBPACK_IMPORTED_MODULE_1__.a[order.shippingOptions.shippingMethod]},getOrderTotal:function getOrderTotal(order){var orderItemsTotal=Order.getOrderItemsTotal(order),shippingCharges=Order.getShippingCharges(order);return{orderItemsTotal:orderItemsTotal,shippingCharges:shippingCharges,orderTotal:orderItemsTotal+shippingCharges}}}},495:function(module,exports){},496:function(module,exports){},513:function(module,exports,__webpack_require__){module.exports={langSelect:"Header_langSelect__204DC"}},516:function(module,exports,__webpack_require__){__webpack_require__(517),__webpack_require__(689),__webpack_require__(690),__webpack_require__(843),__webpack_require__(1062),__webpack_require__(1094),__webpack_require__(1099),__webpack_require__(1111),__webpack_require__(1113),__webpack_require__(1118),__webpack_require__(1120),module.exports=__webpack_require__(1133)},591:function(module,exports){},690:function(module,__webpack_exports__,__webpack_require__){"use strict";__webpack_require__.r(__webpack_exports__);__webpack_require__(223)}},[[516,1,2]]]);
2 | //# sourceMappingURL=main.22514c02e870346d0f24.bundle.js.map
--------------------------------------------------------------------------------
/docs/main.22514c02e870346d0f24.bundle.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"main.22514c02e870346d0f24.bundle.js","sources":["webpack:///main.22514c02e870346d0f24.bundle.js"],"mappings":"AAAA","sourceRoot":""}
--------------------------------------------------------------------------------
/docs/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Checkout Form",
3 | "name": "Checkout Form",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/docs/runtime~main.22514c02e870346d0f24.bundle.js:
--------------------------------------------------------------------------------
1 | !function(modules){function webpackJsonpCallback(data){for(var moduleId,chunkId,chunkIds=data[0],moreModules=data[1],executeModules=data[2],i=0,resolves=[];i
24 | * @license MIT
25 | */
26 |
27 | /*!
28 | * https://github.com/es-shims/es5-shim
29 | * @license es5-shim Copyright 2009-2020 by contributors, MIT License
30 | * see https://github.com/es-shims/es5-shim/blob/master/LICENSE
31 | */
32 |
33 | /*!
34 | * https://github.com/paulmillr/es6-shim
35 | * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)
36 | * and contributors, MIT License
37 | * es6-shim: v0.35.4
38 | * see https://github.com/paulmillr/es6-shim/blob/0.35.3/LICENSE
39 | * Details and documentation:
40 | * https://github.com/paulmillr/es6-shim/
41 | */
42 |
43 | /*!
44 | * is-plain-object
45 | *
46 | * Copyright (c) 2014-2017, Jon Schlinkert.
47 | * Released under the MIT License.
48 | */
49 |
50 | /*!
51 | * isobject
52 | *
53 | * Copyright (c) 2014-2017, Jon Schlinkert.
54 | * Released under the MIT License.
55 | */
56 |
57 | /*! *****************************************************************************
58 | Copyright (c) Microsoft Corporation.
59 |
60 | Permission to use, copy, modify, and/or distribute this software for any
61 | purpose with or without fee is hereby granted.
62 |
63 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
64 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
65 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
66 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
67 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
68 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
69 | PERFORMANCE OF THIS SOFTWARE.
70 | ***************************************************************************** */
71 |
72 | /*! @preserve
73 | * numeral.js
74 | * version : 2.0.6
75 | * author : Adam Draper
76 | * license : MIT
77 | * http://adamwdraper.github.com/Numeral-js/
78 | */
79 |
80 | /**
81 | * Prism: Lightweight, robust, elegant syntax highlighting
82 | *
83 | * @license MIT
84 | * @author Lea Verou
85 | * @namespace
86 | * @public
87 | */
88 |
89 | /** @license React v0.20.1
90 | * scheduler.production.min.js
91 | *
92 | * Copyright (c) Facebook, Inc. and its affiliates.
93 | *
94 | * This source code is licensed under the MIT license found in the
95 | * LICENSE file in the root directory of this source tree.
96 | */
97 |
98 | /** @license React v16.13.1
99 | * react-is.production.min.js
100 | *
101 | * Copyright (c) Facebook, Inc. and its affiliates.
102 | *
103 | * This source code is licensed under the MIT license found in the
104 | * LICENSE file in the root directory of this source tree.
105 | */
106 |
107 | /** @license React v17.0.1
108 | * react-dom.production.min.js
109 | *
110 | * Copyright (c) Facebook, Inc. and its affiliates.
111 | *
112 | * This source code is licensed under the MIT license found in the
113 | * LICENSE file in the root directory of this source tree.
114 | */
115 |
116 | /** @license React v17.0.1
117 | * react-jsx-runtime.production.min.js
118 | *
119 | * Copyright (c) Facebook, Inc. and its affiliates.
120 | *
121 | * This source code is licensed under the MIT license found in the
122 | * LICENSE file in the root directory of this source tree.
123 | */
124 |
125 | /** @license React v17.0.1
126 | * react.production.min.js
127 | *
128 | * Copyright (c) Facebook, Inc. and its affiliates.
129 | *
130 | * This source code is licensed under the MIT license found in the
131 | * LICENSE file in the root directory of this source tree.
132 | */
133 |
134 | //! stable.js 0.1.8, https://github.com/Two-Screen/stable
135 |
136 | //! © 2018 Angry Bytes and contributors. MIT licensed.
137 |
--------------------------------------------------------------------------------
/docs/vendors~main.22514c02e870346d0f24.bundle.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"vendors~main.22514c02e870346d0f24.bundle.js","sources":["webpack:///vendors~main.22514c02e870346d0f24.bundle.js"],"mappings":";AAAA","sourceRoot":""}
--------------------------------------------------------------------------------
/docs/vendors~main.33c5a3c5c6b3b33439d9.bundle.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*
2 | object-assign
3 | (c) Sindre Sorhus
4 | @license MIT
5 | */
6 |
7 | /*!
8 | Copyright (c) 2017 Jed Watson.
9 | Licensed under the MIT License (MIT), see
10 | http://jedwatson.github.io/classnames
11 | */
12 |
13 | /*!
14 | * Fuse.js v3.6.1 - Lightweight fuzzy-search (http://fusejs.io)
15 | *
16 | * Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me)
17 | * All Rights Reserved. Apache Software License 2.0
18 | *
19 | * http://www.apache.org/licenses/LICENSE-2.0
20 | */
21 |
22 | /*!
23 | * OverlayScrollbars
24 | * https://github.com/KingSora/OverlayScrollbars
25 | *
26 | * Version: 1.12.0
27 | *
28 | * Copyright KingSora | Rene Haas.
29 | * https://github.com/KingSora
30 | *
31 | * Released under the MIT license.
32 | * Date: 05.04.2020
33 | */
34 |
35 | /*!
36 | * https://github.com/es-shims/es5-shim
37 | * @license es5-shim Copyright 2009-2020 by contributors, MIT License
38 | * see https://github.com/es-shims/es5-shim/blob/master/LICENSE
39 | */
40 |
41 | /*!
42 | * https://github.com/paulmillr/es6-shim
43 | * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com)
44 | * and contributors, MIT License
45 | * es6-shim: v0.35.4
46 | * see https://github.com/paulmillr/es6-shim/blob/0.35.3/LICENSE
47 | * Details and documentation:
48 | * https://github.com/paulmillr/es6-shim/
49 | */
50 |
51 | /*!
52 | * isobject
53 | *
54 | * Copyright (c) 2014-2017, Jon Schlinkert.
55 | * Released under the MIT License.
56 | */
57 |
58 | /**
59 | * Prism: Lightweight, robust, elegant syntax highlighting
60 | *
61 | * @license MIT
62 | * @author Lea Verou
63 | * @namespace
64 | * @public
65 | */
66 |
67 | /** @license React v0.19.1
68 | * scheduler.production.min.js
69 | *
70 | * Copyright (c) Facebook, Inc. and its affiliates.
71 | *
72 | * This source code is licensed under the MIT license found in the
73 | * LICENSE file in the root directory of this source tree.
74 | */
75 |
76 | /** @license React v16.13.1
77 | * react-dom.production.min.js
78 | *
79 | * Copyright (c) Facebook, Inc. and its affiliates.
80 | *
81 | * This source code is licensed under the MIT license found in the
82 | * LICENSE file in the root directory of this source tree.
83 | */
84 |
85 | /** @license React v16.13.1
86 | * react-is.production.min.js
87 | *
88 | * Copyright (c) Facebook, Inc. and its affiliates.
89 | *
90 | * This source code is licensed under the MIT license found in the
91 | * LICENSE file in the root directory of this source tree.
92 | */
93 |
94 | /** @license React v16.13.1
95 | * react.production.min.js
96 | *
97 | * Copyright (c) Facebook, Inc. and its affiliates.
98 | *
99 | * This source code is licensed under the MIT license found in the
100 | * LICENSE file in the root directory of this source tree.
101 | */
102 |
103 | //! stable.js 0.1.8, https://github.com/Two-Screen/stable
104 |
105 | //! © 2018 Angry Bytes and contributors. MIT licensed.
106 |
--------------------------------------------------------------------------------