@commercetools-uikit/money-input v0.0.0-canary-2021431153416
MoneyInput
Description
A controlled input component for money values with validation states.
Installation
yarn add @commercetools-uikit/money-inputnpm --save install @commercetools-uikit/money-inputAdditionally install the peer dependencies (if not present)
yarn add react react-dom react-intlnpm --save install react react-dom react-intlUsage
import MoneyInput from '@commercetools-uikit/money-input';
const Example = () => (
<MoneyInput
value={{ amount: '1.00', currencyCode: 'EUR' }}
onChange={
(/** event */) => {
// alert(event.target.name, event.target.value)
}
}
currencies={['EUR', 'USD']}
/>
);
export default Example;Properties
| Props | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Used as HTML id property. An id is auto-generated when it is not specified. | ||
autoComplete | string | Used as HTML autocomplete property | ||
aria-invalid | boolean | Indicate if the value entered in the input is invalid. | ||
aria-errormessage | string | HTML ID of an element containing an error message related to the input. | ||
name | string | The prefix used to create a HTML name property for the amount input field (${name}.amount) and the currency dropdown (${name}.currencyCode). | ||
value | ObjectSee signature. | ✅ | Value of the input. Consists of the currency code and an amount. amount is a string representing the amount. A dot has to be used as the decimal separator. | |
currencies | Array: string[] | [] | List of possible currencies. When not provided or empty, the component renders a label with the value's currency instead of a dropdown. | |
placeholder | string | Placeholder text for the input | ||
onBlur | FunctionSee signature. | Called when input is blurred | ||
onFocus | FunctionSee signature. | Called when input is focused | ||
isCondensed | boolean | Use this property to reduce the paddings of the component for a ui compact variant | ||
isDisabled | boolean | Indicates that the input cannot be modified (e.g not authorized, or changes currently saving). | ||
isReadOnly | boolean | Indicates that the field is displaying read-only content | ||
isAutofocussed | boolean | Focus the input on initial render | ||
onChange | FunctionSee signature. | Called with the event of the input or dropdown when either the currency or the amount have changed. | ||
menuPortalTarget | ReactSelectProps['menuPortalTarget'] | Dom element to portal the currency select menu to Props from React select was used | ||
menuPortalZIndex | number | 1 | z-index value for the currency select menu portal
Use in conjunction with menuPortalTarget | |
menuShouldBlockScroll | ReactSelectProps['menuShouldBlockScroll'] | whether the menu should block scroll while open Props from React select was used | ||
hasError | boolean | Indicates that input has errors | ||
hasWarning | boolean | Control to indicate on the input if there are selected values that are potentially invalid | ||
hasHighPrecisionBadge | boolean | Shows high precision badge in case current value uses high precision. | ||
horizontalConstraint | unionPossible values:, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 'scale', 'auto' | 'scale' | Horizontal size limit of the input fields. | |
isCurrencyInputDisabled | boolean | Indicates that the currency input cannot be modified. |
Signatures
Signature value
{
amount: string;
currencyCode: TCurrencyCode | '';
}Signature onBlur
(event: TCustomEvent) => voidSignature onFocus
(event: TCustomEvent) => voidSignature onChange
(event: TCustomEvent) => voidStatic methods
MoneyInput.convertToMoneyValue
The convertToMoneyValue function will turn a MoneyInput value into a MoneyValue the API can handle. It automatically converts to centPrecision or highPrecision types when the number of supplied fraction digits exceeds the number of fraction digits used by the currency.
If you want to forbid highPrecision, then the form's validation needs to add an error when it sees a highPrecision price. See example below.
Here are examples of centPrecision and highPrecision prices.
// 42.00 €
{
"type": "centPrecision",
"currencyCode": "EUR",
"centAmount": 4200,
"fractionDigits": 2
}// 0.0123456 €
{
"type": "highPrecision",
"currencyCode": "EUR",
"centAmount": 1,
"preciseAmount": 123456,
"fractionDigits": 7
}MoneyInput.parseMoneyValue
The parseMoneyValue function will turn a MoneyValue into a value the MoneyInput component can handle ({ amount, currencyCode }).
MoneyInput.isEmpty
The isEmpty function will return true when the passed MoneyInput value is empty (either has no currency or no amount, or does not exist at all).
MoneyInput.isEmpty({ amount: '', currencyCode: 'EUR' }); // -> true
MoneyInput.isEmpty({ amount: '5', currencyCode: '' }); // -> true
MoneyInput.isEmpty(); // -> true
MoneyInput.isEmpty({ amount: '5', currencyCode: 'EUR' }); // -> falseMoneyInput.isTouched
The isTouched function will return true when all input elements were touched (currency dropdown and amount input).
MoneyInput.isTouched({ amount: true, currencyCode: true }); // -> true
MoneyInput.isTouched({ amount: true }); // -> false
MoneyInput.isTouched({ currencyCode: true }); // -> false
MoneyInput.isTouched({ amount: false, currencyCode: false }); // -> false
MoneyInput.isTouched({}); // -> falseMoneyInput.getCurrencyDropdownId
getCurrencyDropdownId(idPrefix)
Returns the id of the currency dropdown. This is useful in case you want to create a label for the input field. You can use it as
MoneyInput.getCurrencyDropdownId('price');
// -> "price.currencyCode"MoneyInput.getAmountInputId(idPrefix)
Returns the id of the amount input. This is useful in case you want to create a label for the input field. You can use it as
MoneyInput.getAmountInputId('price');
// -> "price.amount"MoneyInput.isHighPrecision
The isHighPrecision function will return true when a MoneyInput value is passed for which the number of fraction digits of the amount exceeds the number of fraction digits the supplied currency usually uses.
The function may not be called with empty money values. It will throw in those cases.
MoneyInput.isHighPrecision({ amount: '2.00', currencyCode: 'EUR' }, 'en'); // -> false
MoneyInput.isHighPrecision({ amount: '2.001', currencyCode: 'EUR' }, 'en'); // -> true
MoneyInput.isHighPrecision({ amount: '2.001', currencyCode: 'EUR' }, 'de'); // -> false
MoneyInput.isHighPrecision({ amount: '2,001', currencyCode: 'EUR' }, 'de'); // -> true
MoneyInput.isHighPrecision({ amount: '', currencyCode: 'EUR' }, 'en'); // -> throwsExamples
Here's an example of how MoneyInput would be used inside a form.
import { IntlProvider } from 'react-intl';
import { Formik } from 'formik';
import omitEmpty from 'omit-empty-es';
import { ErrorMessage } from '@commercetools-uikit/messages';
import MoneyInput from '@commercetools-uikit/money-input';
const currencies = ['EUR', 'USD', 'AED', 'KWD'];
// the existing document, e.g. from the database
const doc = {
somePrice: {
type: 'centPrecision',
currencyCode: 'EUR',
centAmount: 4200,
fractionDigits: 2,
},
};
// A function to convert a document to form values.
const docToFormValues = (aDoc) => ({
// The parseMoneyValue function will turn a MoneyValue into a
// value the MoneyInput component can handle ({ amount, currencyCode })
somePrice: MoneyInput.parseMoneyValue(aDoc.somePrice),
});
// a function to convert form values back to a document
const formValuesToDoc = (formValues, locale) => ({
// The convertToMoneyValue function will turn a MoneyInput
// value into a value the API can handle
// It automatically converts to centPrecision or highPrecision
// depending on the number of supplied fraction digits and the
// used currency code.
// If you want to forbid highPrecision, then the form's validation
// needs to add an error when it sees a highPrecision price.
// See example below
somePrice: MoneyInput.convertToMoneyValue(formValues.somePrice, locale),
});
const validate = (formValues, locale) => {
const errors = { somePrice: {} };
const moneyValue = MoneyInput.convertToMoneyValue(
formValues.somePrice,
locale
);
// convertToMoneyValue returns null whenever the value is invalid
if (!moneyValue) {
errors.somePrice.missing = true;
} else if (moneyValue.type === 'highPrecision') {
// This form does not allow highPrecision prices
errors.somePrice.highPrecision = true;
}
return omitEmpty(errors);
};
const initialValues = docToFormValues(doc);
return (
<Formik
initialValues={initialValues}
validate={validate}
onSubmit={(formValues) => {
// doc will contain "somePrice" holding a MoneyValue,
// ready to be consumed by the API
const nextDoc = formValuesToDoc(formValues);
console.log(nextDoc);
}}
render={({
values,
errors,
touched,
setFieldValue,
setFieldTouched,
handleSubmit,
isSubmitting,
}) => (
<form onSubmit={handleSubmit}>
<MoneyInput
value={values.somePrice}
currencies={currencies}
onBlur={() => setFieldTouched('somePrice')}
isDisabled={isSubmitting}
onChange={(value) => setFieldValue('somePrice', value)}
hasError={
MoneyInput.isTouched(touched.somePrice) && Boolean(errors.somePrice)
}
horizontalConstraint={10}
/>
{touched.somePrice && errors.somePrice && errors.somePrice.missing && (
<ErrorMessage>This field is required!</ErrorMessage>
)}
{touched.somePrice &&
errors.somePrice &&
errors.somePrice.highPrecision && (
<ErrorMessage>
High precision prices are not supported here!
</ErrorMessage>
)}
<button type="submit">Submit</button>
</form>
)}
/>
);1 year ago
8 months ago
11 months ago
10 months ago
11 months ago
11 months ago
7 months ago
11 months ago
11 months ago
7 months ago
8 months ago
12 months ago
11 months ago
8 months ago
8 months ago
8 months ago
1 year ago
7 months ago
7 months ago
11 months ago
1 year ago
9 months ago
1 year ago
11 months ago
10 months ago
7 months ago
1 year ago
7 months ago
7 months ago
11 months ago
1 year ago
1 year ago
7 months ago
7 months ago
1 year ago
10 months ago
8 months ago
7 months ago
10 months ago
1 year ago
1 year ago
7 months ago
11 months ago
8 months ago
1 year ago
7 months ago
8 months ago
1 year ago
10 months ago
10 months ago
11 months ago
11 months ago
10 months ago
10 months ago
10 months ago
10 months ago
1 year ago
10 months ago
11 months ago
1 year ago
8 months ago
10 months ago
1 year ago
1 year ago
7 months ago
1 year ago
8 months ago
1 year ago
1 year ago
10 months ago
11 months ago
7 months ago
1 year ago
7 months ago
12 months ago
8 months ago
11 months ago
11 months ago
10 months ago
1 year ago
8 months ago
7 months ago
8 months ago
1 year ago
1 year ago
1 year ago
11 months ago
7 months ago
6 months ago
1 year ago
11 months ago
11 months ago
1 year ago
1 year ago
7 months ago
7 months ago
7 months ago
11 months ago
8 months ago
1 year ago
8 months ago
1 year ago
11 months ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
1 year ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
1 year ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago