Skip to content

Commit

Permalink
Validate address on contact screen (#174)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kamill90 authored and Kamil Lewandowski committed Jul 22, 2020
1 parent c30110c commit e107b43
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 14 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@types/react-native": "^0.61.23",
"@types/react-native-share": "^3.1.0",
"@types/react-native-snap-carousel": "^3.8.1",
"@types/react-navigation": "^3.4.0",
"@types/react-redux": "^7.1.7",
"@types/react-test-renderer": "^16.9.0",
"@types/uuid": "^3.4.8",
Expand Down
2 changes: 2 additions & 0 deletions src/components/GenericInputItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface Props {
title: string;
value?: string;
validate?: (value: string) => string | undefined;
validateOnSave?: (value: string) => void;
onSave?: (value: string) => void;
}

Expand All @@ -27,6 +28,7 @@ export const GenericInputItem = (props: Props) => {
label,
value,
validate: props.validate,
validateOnSave: props.validateOnSave,
onSave: handleValueSave,
});
};
Expand Down
1 change: 1 addition & 0 deletions src/consts/models.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export type RootStackParams = {
header?: React.ReactNode;
value?: string;
validate?: (value: string) => string | undefined;
validateOnSave?: (value: string) => void;
keyboardType?: KeyboardType;
};
[Route.Message]: {
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/DataProcessing.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const bitcoin = require('bitcoinjs-lib');

export const processAddressData = (data: string, stateAmount?: any) => {
const regex = /[?&]([^=#]+)=([^&#]*)/g;
const solvedData = regex.exec(data);
Expand All @@ -21,3 +23,5 @@ export const processAddressData = (data: string, stateAmount?: any) => {

return newAddresses;
};

export const checkAddress = (address: string) => bitcoin.address.toOutputScript(address);
6 changes: 6 additions & 0 deletions src/screens/ContactDetailsScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from 'app/components';
import { CopyButton } from 'app/components/CopyButton';
import { Contact, Route, MainCardStackNavigatorParams, RootStackParams } from 'app/consts';
import { checkAddress } from 'app/helpers/DataProcessing';
import { UpdateContactAction, updateContact } from 'app/state/contacts/actions';

const i18n = require('../../loc');
Expand Down Expand Up @@ -53,6 +54,10 @@ export class ContactDetailsScreen extends React.PureComponent<Props, State> {
this.saveChanges({ address });
};

validateAddress = (address: string) => {
checkAddress(address);
};

saveChanges = (changes: Partial<Contact>) => {
const { contact } = this.props.route.params;
const updatedContact = { ...contact, ...changes };
Expand Down Expand Up @@ -114,6 +119,7 @@ export class ContactDetailsScreen extends React.PureComponent<Props, State> {
title={i18n.contactDetails.editAddress}
label={i18n.contactDetails.addressLabel}
value={address}
validateOnSave={this.validateAddress}
onSave={this.setAddress}
/>
<CopyButton textToCopy={address} containerStyle={styles.copyButtonContainer} />
Expand Down
38 changes: 27 additions & 11 deletions src/screens/CreateContactScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { v4 as uuidv4 } from 'uuid';
import { icons } from 'app/assets';
import { Button, Header, InputItem, ScreenTemplate, Text, Image } from 'app/components';
import { Contact, Route, MainTabNavigatorParams, MainCardStackNavigatorParams } from 'app/consts';
import { checkAddress } from 'app/helpers/DataProcessing';
import { CreateMessage, MessageType } from 'app/helpers/MessageCreator';
import { createContact, CreateContactAction } from 'app/state/contacts/actions';
import { palette, typography } from 'app/styles';
Expand All @@ -25,12 +26,14 @@ interface Props {
interface State {
name: string;
address: string;
error: string;
}

export class CreateContactScreen extends React.PureComponent<Props, State> {
state: State = {
name: '',
address: '',
error: '',
};

get canCreateContact(): boolean {
Expand All @@ -39,23 +42,35 @@ export class CreateContactScreen extends React.PureComponent<Props, State> {

setName = (name: string) => this.setState({ name });

setAddress = (address: string) => this.setState({ address });
setAddress = (address: string) => this.setState({ address, error: '' });

onBarCodeScan = (address: string) => {
this.setAddress(address.split('?')[0].replace('bitcoin:', ''));
};

createContact = () => {
this.props.createContact({
id: uuidv4(),
name: this.state.name.trim(),
address: this.state.address.trim(),
});
this.showSuccessImportMessageScreen();
this.setState({
name: '',
address: '',
});
try {
this.validateAddress();
if (this.state.error) return;
this.props.createContact({
id: uuidv4(),
name: this.state.name.trim(),
address: this.state.address.trim(),
});
this.showSuccessImportMessageScreen();
this.setState({
name: '',
address: '',
});
} catch (_) {
this.setState({
error: i18n.send.details.address_field_is_not_valid,
});
}
};

validateAddress = () => {
checkAddress(this.state.address);
};

onScanQrCodePress = () => {
Expand Down Expand Up @@ -95,6 +110,7 @@ export class CreateContactScreen extends React.PureComponent<Props, State> {
<InputItem setValue={this.setName} label={i18n.contactCreate.nameLabel} />
<View>
<InputItem
error={this.state.error}
focused={!!address}
value={address}
multiline
Expand Down
12 changes: 11 additions & 1 deletion src/screens/EditTextScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,19 @@ export const EditTextScreen = (props: Props) => {
const { label, header, onSave, title } = params;
const keyboardType = params.keyboardType || 'default';
const validate = params.validate || null;
const validateOnSave = params.validateOnSave || null;
const [value, setValue] = useState(params.value || '');
const [error, setError] = useState('');

const handlePressOnSaveButton = () => {
if (validateOnSave) {
try {
validateOnSave(value);
} catch (err) {
setError(i18n.send.details.address_field_is_not_valid);
return;
}
}
onSave(value);
props.navigation.pop();
};
Expand All @@ -43,7 +53,7 @@ export const EditTextScreen = (props: Props) => {
value={value}
setValue={setValue}
autoFocus={true}
error={!!validate && validate(value)}
error={error || (value && !!validate && validate(value)) || ''}
keyboardType={keyboardType as KeyboardType}
/>
</View>
Expand Down
51 changes: 49 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,16 @@
color "^3.1.2"
react-native-iphone-x-helper "^1.2.1"

"@react-navigation/core@^3.7.6":
version "3.7.6"
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-3.7.6.tgz#e0244fcdc22937825b252197f70308bbe5709c58"
integrity sha512-loYFIn0Boy7C+vYxwcqsBVRFRO1EizZJErdutE6/3Jw6dbzz3Bnzupbw5hckZNB16GckacMwGoepZNIK51IIcg==
dependencies:
hoist-non-react-statics "^3.3.2"
path-to-regexp "^1.8.0"
query-string "^6.11.1"
react-is "^16.13.0"

"@react-navigation/core@^5.11.1":
version "5.11.1"
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-5.11.1.tgz#c4890910ba3d6332ee6873f0adb3d3d13cf4fa4c"
Expand All @@ -1277,6 +1287,14 @@
react-is "^16.13.0"
use-subscription "^1.4.0"

"@react-navigation/native@^3.8.0":
version "3.8.0"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-3.8.0.tgz#35882c3fc2f997ea1a43c12a15088cf4c818fd92"
integrity sha512-Uym5XdNOTpTR6XC4IVa/Shfn12DUF3DUIqch+cpiLNfvauQukVmWoz+Rfxd2faGOzxT12EhrWGFsMJ/8nuTfcw==
dependencies:
hoist-non-react-statics "^3.3.2"
react-native-safe-area-view "^0.14.9"

"@react-navigation/native@^5.6.1":
version "5.6.1"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-5.6.1.tgz#a603b921f39fe3fcfcc27232d71b24e80effc1f2"
Expand Down Expand Up @@ -1583,6 +1601,13 @@
dependencies:
"@types/react" "*"

"@types/react-navigation@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@types/react-navigation/-/react-navigation-3.4.0.tgz#d610d13c9162312079a8ca102660143f07432cbf"
integrity sha512-Y7F5zU8BTBK8tEOvUqgvwvPZ7+9vnc2UI1vHwJ/9ZJG98TntNv04GWa6lrn4MA4149pqw6cyNw/V49Yd2osAFQ==
dependencies:
react-navigation "*"

"@types/react-redux@^7.1.7":
version "7.1.9"
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.9.tgz#280c13565c9f13ceb727ec21e767abe0e9b4aec3"
Expand Down Expand Up @@ -4678,7 +4703,7 @@ hoist-non-react-statics@^2.3.1:
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==

hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1:
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
Expand Down Expand Up @@ -7287,6 +7312,13 @@ path-parse@^1.0.6:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==

path-to-regexp@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
dependencies:
isarray "0.0.1"

path-type@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
Expand Down Expand Up @@ -7627,7 +7659,7 @@ query-string@5:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"

query-string@^6.13.1:
query-string@^6.11.1, query-string@^6.13.1:
version "6.13.1"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.13.1.tgz#d913ccfce3b4b3a713989fe6d39466d92e71ccad"
integrity sha512-RfoButmcK+yCta1+FuU8REvisx1oEzhMKwhLUNcepQTPGcNMp1sIqjnfCtfnvGSQZQEhaBHvccujtWoUV3TTbA==
Expand Down Expand Up @@ -7923,6 +7955,13 @@ react-native-safe-area-context@^3.0.6:
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.0.6.tgz#ee180f53f9f40f8302923b9c09d821cf8ada01eb"
integrity sha512-/McWHgRG3CjXo/1ctlxH3mjW2psjf/QYAt9kWUTEtHu4b6z1y4hfUIGuYEJ02asaS1ixPsYrkqVqwzTv4olUMQ==

react-native-safe-area-view@^0.14.9:
version "0.14.9"
resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.14.9.tgz#90ee8383037010d9a5055a97cf97e4c1da1f0c3d"
integrity sha512-WII/ulhpVyL/qbYb7vydq7dJAfZRBcEhg4/UWt6F6nAKpLa3gAceMOxBxI914ppwSP/TdUsandFy6lkJQE0z4A==
dependencies:
hoist-non-react-statics "^2.3.1"

react-native-safe-modules@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-native-safe-modules/-/react-native-safe-modules-1.0.0.tgz#10a918adf97da920adb1e33e0c852b1e80123b65"
Expand Down Expand Up @@ -8034,6 +8073,14 @@ react-native@0.61.5:
stacktrace-parser "^0.1.3"
whatwg-fetch "^3.0.0"

react-navigation@*:
version "4.4.0"
resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-4.4.0.tgz#c5523669df642aab23ff9e2ceb2109d3492a9374"
integrity sha512-BtxqNNlEGm/ve1mGHxCvrtvDzZ+2OF/V9OJaDPz/Cdx2VvYiFGaq6mtlFQm5/2bLxiEVXhNFcYSTCP26YGiENA==
dependencies:
"@react-navigation/core" "^3.7.6"
"@react-navigation/native" "^3.8.0"

react-redux@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d"
Expand Down

0 comments on commit e107b43

Please sign in to comment.