Skip to content

Commit

Permalink
fix: refactor contact add
Browse files Browse the repository at this point in the history
  • Loading branch information
limpbrains committed Nov 29, 2023
1 parent 64a84d9 commit 45dae0b
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 60 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/e2e-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
- name: Restart docker before last attempt
if: steps.test1.outcome != 'success' && steps.test2.outcome != 'success' && steps.test3.outcome != 'success'
run: |
cd docker && docker-compose down && docker-compose up -d && cd ..
cd docker && docker-compose down -t 60 && docker-compose up -d && cd ..
while ! nc -z '127.0.0.1' 60001; do sleep 1; done
- name: Test attempt 4
Expand Down
7 changes: 5 additions & 2 deletions e2e/slashtags.e2e.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,13 @@ d('Profile and Contacts', () => {

// self
await element(by.id('AddContact')).tap();
await element(by.id('ContactURLInput')).typeText(slashtagsUrl + '\n');
await expect(element(by.id('ContactError'))).toBeVisible();
await element(by.id('ContactURLInput')).typeText(slashtagsUrl);
await element(by.id('AddContactButton')).tap();
await expect(element(by.id('ContactURLInput-error'))).toBeVisible();

// Satoshi
await element(by.id('ContactURLInput')).replaceText(satoshi.url);
await element(by.id('AddContactButton')).tap();
await waitFor(element(by.id('NameInput')))
.toBeVisible()
.withTimeout(30000);
Expand All @@ -147,6 +149,7 @@ d('Profile and Contacts', () => {
// Hal
await element(by.id('AddContact')).tap();
await element(by.id('ContactURLInput')).replaceText(hal.url);
await element(by.id('AddContactButton')).tap();
await waitFor(element(by.id('NameInput')))
.toBeVisible()
.withTimeout(30000);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"@synonymdev/slashtags-keychain": "1.0.0",
"@synonymdev/slashtags-profile": "1.0.2",
"@synonymdev/slashtags-sdk": "1.0.0-alpha.38",
"@synonymdev/slashtags-url": "1.0.0-alpha.4",
"@synonymdev/slashtags-url": "1.0.1",
"@synonymdev/slashtags-widget-bitcoin-feed": "1.0.0",
"@synonymdev/slashtags-widget-facts-feed": "1.1.0",
"@synonymdev/slashtags-widget-news-feed": "1.1.0",
Expand Down
38 changes: 32 additions & 6 deletions src/components/LabeledInput.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { ReactElement, RefObject } from 'react';
import { View, StyleSheet, ViewStyle, StyleProp } from 'react-native';
import { TextInput, BottomSheetTextInput } from '../styles/components';
import { Caption13Up } from '../styles/text';
import { Caption13Up, Text02S } from '../styles/text';
import { IThemeColors } from '../styles/themes';

type LabeledInputProps = {
label: string;
error?: string;
children?: JSX.Element | JSX.Element[];
ref?: RefObject<any>;
autoFocus?: boolean;
Expand All @@ -17,10 +19,12 @@ type LabeledInputProps = {
onChange?: (value: string) => void;
maxLength?: number;
testID?: string;
color?: keyof IThemeColors;
};

const LabeledInput = ({
label,
error,
children,
ref,
autoFocus,
Expand All @@ -33,6 +37,7 @@ const LabeledInput = ({
style,
maxLength,
testID,
color = 'white',
}: LabeledInputProps): ReactElement => {
const numberOfChildren = React.Children.toArray(children).length;

Expand All @@ -41,9 +46,19 @@ const LabeledInput = ({

return (
<View style={style}>
<Caption13Up color="gray1" style={styles.label}>
{label}
</Caption13Up>
<View style={styles.header}>
<Caption13Up style={styles.label} color="gray1">
{label}
</Caption13Up>
{error && (
<Text02S
color="brand"
style={styles.error}
testID={testID ? testID + '-error' : undefined}>
{error}
</Text02S>
)}
</View>
<View style={onChange ? styles.inputContainer : styles.readOnlyInput}>
{bottomSheet ? (
<BottomSheetTextInput
Expand All @@ -60,12 +75,12 @@ const LabeledInput = ({
editable={!!onChange}
returnKeyType={returnKeyType}
testID={testID}
color={color}
/>
) : (
<TextInput
style={textInputStyle}
defaultValue={value}
color="white"
autoCapitalize="none"
autoCorrect={false}
autoFocus={autoFocus}
Expand All @@ -77,6 +92,7 @@ const LabeledInput = ({
returnKeyType={returnKeyType}
maxLength={maxLength}
testID={testID}
color={color}
/>
)}
{children && (
Expand All @@ -97,9 +113,19 @@ const LabeledInput = ({
};

const styles = StyleSheet.create({
label: {
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
flexWrap: 'wrap',
marginBottom: 8,
},
label: {
marginRight: 8,
},
error: {
marginVertical: -1,
},
inputContainer: {
position: 'relative',
},
Expand Down
115 changes: 69 additions & 46 deletions src/screens/Contacts/AddContact.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import React, { ReactElement, useState } from 'react';
import { View, StyleSheet, TouchableOpacity } from 'react-native';
import { StackNavigationProp } from '@react-navigation/stack';
import Clipboard from '@react-native-clipboard/clipboard';
import { useTranslation } from 'react-i18next';
import { SlashURL } from '@synonymdev/slashtags-sdk';
import { parse } from '@synonymdev/slashtags-url';
import { useTranslation } from 'react-i18next';

import { closeBottomSheet } from '../../store/actions/ui';
import { handleSlashtagURL } from '../../utils/slashtags';
Expand All @@ -15,10 +14,12 @@ import {
useBottomSheetBackPress,
useSnapPoints,
} from '../../hooks/bottomSheet';
import { Text01S, Text02S } from '../../styles/text';
import { Text01S } from '../../styles/text';
import { ClipboardTextIcon, CornersOutIcon } from '../../styles/icons';
import type { RootStackParamList } from '../../navigation/types';
import { useSelectedSlashtag2 } from '../../hooks/slashtags2';
import Button from '../../components/Button';
import SafeAreaInset from '../../components/SafeAreaInset';

const AddContact = ({
navigation,
Expand All @@ -27,57 +28,63 @@ const AddContact = ({
}): ReactElement => {
const { t } = useTranslation('slashtags');
const snapPoints = useSnapPoints('small');
const [addContactURL, setAddContactURL] = useState('');
const [error, setError] = useState<boolean | string>(false);
const [url, setUrl] = useState('');
const [error, setError] = useState<undefined | string>();
const { url: myProfileURL } = useSelectedSlashtag2();

useBottomSheetBackPress('addContactModal');

const updateContactID = (url: string): void => {
setAddContactURL(url);
setError(false);
const handleChangeUrl = (contactUrl: string): void => {
setUrl(contactUrl);
setError(undefined);
};

if (url === '') {
const handleAddContact = (contactUrl?: string): void => {
contactUrl = contactUrl ?? url;
setError(undefined);
if (!contactUrl) {
return;
}

try {
if (parse(url).id === parse(myProfileURL).id) {
parse(contactUrl);
} catch (e) {
setError(t('contact_error_key'));
return;
}

try {
if (parse(contactUrl).id === parse(myProfileURL).id) {
setError(t('contact_error_yourself'));
return;
}
} catch (e) {}

if (!url.startsWith('slash:')) {
// Handle z32 key without slash: scheme prefix
try {
SlashURL.decode(url);
handleSlashtagURL('slash:' + url, onError, onContact);
} catch {
onError();
}
} else {
handleSlashtagURL(url, onError, onContact);
}

function onError(): void {
const onError = (): void => {
setError(t('contact_error_key'));
}
};

function onContact(): void {
setAddContactURL('');
const onContact = (): void => {
setUrl('');
closeBottomSheet('addContactModal');
}
};

handleSlashtagURL(contactUrl, onError, onContact);
};

const updateContactID = async (contactUrl: string): Promise<void> => {
setUrl(contactUrl);
handleAddContact(contactUrl);
};

const pasteAddContact = async (): Promise<void> => {
let url = await Clipboard.getString();
url = url.trim();
updateContactID(url);
const handlePaste = async (): Promise<void> => {
let contactUrl = await Clipboard.getString();
contactUrl = contactUrl.trim();
updateContactID(contactUrl);
};

const navigateToScanner = (): void => {
navigation.navigate('Scanner');
const handleScanner = (): void => {
navigation.navigate('Scanner', { onScan: updateContactID });
};

return (
Expand All @@ -97,25 +104,33 @@ const AddContact = ({
<LabeledInput
bottomSheet={true}
label={t('contact_add')}
value={addContactURL}
error={error}
value={url}
placeholder={t('contact_key_paste')}
multiline={true}
onChange={updateContactID}
testID="ContactURLInput">
<TouchableOpacity onPress={navigateToScanner}>
onChange={handleChangeUrl}
testID="ContactURLInput"
color={error ? 'brand' : undefined}>
<TouchableOpacity onPress={handleScanner}>
<CornersOutIcon width={24} height={24} color="brand" />
</TouchableOpacity>
<TouchableOpacity onPress={pasteAddContact}>
<TouchableOpacity onPress={handlePaste}>
<ClipboardTextIcon width={24} height={24} color="brand" />
</TouchableOpacity>
</LabeledInput>
</View>

{error && (
<View style={styles.error} testID="ContactError">
<Text02S color="brand">{error}</Text02S>
</View>
)}
<View style={styles.footer}>
<Button
size="large"
disabled={!url}
style={styles.button}
text={t('contact_add_button')}
onPress={(): void => handleAddContact()}
testID="AddContactButton"
/>
</View>
<SafeAreaInset type="bottom" minPadding={16} />
</View>
</BottomSheetWrapper>
);
Expand All @@ -130,10 +145,18 @@ const styles = StyleSheet.create({
},
addContactNote: {
marginHorizontal: 16,
marginBottom: 56,
marginBottom: 16,
},
error: {
marginTop: 16,
footer: {
paddingHorizontal: 16,
alignItems: 'flex-end',
justifyContent: 'flex-end',
flex: 1,
flexDirection: 'row',
},
button: {
marginBottom: 16,
flex: 1,
},
});

Expand Down
1 change: 1 addition & 0 deletions src/utils/i18n/locales/en/slashtags.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"contact_add": "Add contact",
"contact_add_capital": "Add Contact",
"contact_add_explain": "Add a new contact by scanning their QR or by pasting their key below.",
"contact_add_button": "Add",
"contact_key_paste": "Paste a key",
"contact_error_yourself": "You cannot add yourself as a contact.",
"contact_error_key": "This is not a valid key.",
Expand Down
16 changes: 12 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3326,10 +3326,10 @@
turbo-hash-map "^1.0.3"
ws "^8.8.1"

"@synonymdev/slashtags-url@1.0.0-alpha.4", "@synonymdev/slashtags-url@^1.0.0-alpha.3":
version "1.0.0-alpha.4"
resolved "https://registry.yarnpkg.com/@synonymdev/slashtags-url/-/slashtags-url-1.0.0-alpha.4.tgz#f9f47a59dc57aa5efbb2e9ad0cb2a33399fdca67"
integrity sha512-6+ac8h2MqF0H+h4km4dqmyhomvDvyXB7ny1QsvwwwPNPmyVbSyatjsnGLmEkzpNTVO7PHVCkEbDWGrZmdUVksQ==
"@synonymdev/slashtags-url@1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@synonymdev/slashtags-url/-/slashtags-url-1.0.1.tgz#b1d5d350e4774c1397fdd35a572be17bd93a3b36"
integrity sha512-b5cAc73itbWRur/cp9H+eW8oqamnfLBY8ji8bV0ADXTdfN0xpeR3xJDsgMV1HYkaGvCm5ZVUXioQfCUWdNoqaA==
dependencies:
b4a "^1.6.0"
z32 "^1.0.0"
Expand All @@ -3350,6 +3350,14 @@
b4a "^1.6.0"
z32 "^1.0.0"

"@synonymdev/slashtags-url@^1.0.0-alpha.3":
version "1.0.0-alpha.4"
resolved "https://registry.yarnpkg.com/@synonymdev/slashtags-url/-/slashtags-url-1.0.0-alpha.4.tgz#f9f47a59dc57aa5efbb2e9ad0cb2a33399fdca67"
integrity sha512-6+ac8h2MqF0H+h4km4dqmyhomvDvyXB7ny1QsvwwwPNPmyVbSyatjsnGLmEkzpNTVO7PHVCkEbDWGrZmdUVksQ==
dependencies:
b4a "^1.6.0"
z32 "^1.0.0"

"@synonymdev/slashtags-widget-bitcoin-feed@1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@synonymdev/slashtags-widget-bitcoin-feed/-/slashtags-widget-bitcoin-feed-1.0.0.tgz#5486a6629ef08a9bdb9563a3861dc465f8961906"
Expand Down

0 comments on commit 45dae0b

Please sign in to comment.