Added PIN code and components for the chat

This commit is contained in:
Mykyta 2024-04-10 21:22:06 +03:00
parent 191a33ee3d
commit 8bba9f14d7
15 changed files with 582 additions and 0 deletions

1
globals.js Normal file
View File

@ -0,0 +1 @@
global.TextEncoder = require('text-encoding').TextEncoder;

View File

@ -0,0 +1,12 @@
import EStyleSheet from 'react-native-extended-stylesheet';
import { TextStyle, ViewStyle } from 'react-native';
export default EStyleSheet.create({
input: {
borderWidth: 1,
borderColor: '$borderColor',
paddingVertical: 8,
paddingHorizontal: 16,
borderRadius: 30,
} as ViewStyle,
});

View File

@ -0,0 +1,24 @@
import React, { useEffect, useState } from 'react';
import { TextInput, TextInputProps, ViewStyle } from 'react-native';
import styles from '../../../screens/chat/components/chatsImport.style.tsx';
type ITextInputV2Value = string;
interface ITextInputV2 extends TextInputProps {
value?: ITextInputV2Value;
onChange: (value: ITextInputV2Value) => void;
}
export const TextInputV2 = ({
onChange: parentOnChange,
value: parentValue,
...rest
}: ITextInputV2) => {
const [value, onChange] = useState<ITextInputV2Value>(parentValue || '');
useEffect(() => {
parentOnChange(value);
}, [value]);
return <TextInput {...rest} value={value} onChangeText={onChange} style={styles.input} />;
};

View File

@ -0,0 +1,56 @@
import React, { useEffect, useState } from 'react';
import { Button, Text, TextInput, View } from 'react-native';
import { FormattedMessage, injectIntl } from 'react-intl';
import { useRestoreChatByPin } from '@ecency/ns-query';
import styles from './chatWelcome.style.ts';
import { ChatPinCode } from './chatPinCode.jsx';
import { OrDivider } from '../../../components';
import ChatsImport from './chatsImport.jsx';
import ChatAddNewAccount from './chatAddNewAccount.jsx';
const ChatWelcome = () => {
const [pin, setPin] = useState('');
const {
mutateAsync: restoreByPin,
isError: isRestoreFailed,
isLoading: isRestoreLoading,
} = useRestoreChatByPin();
useEffect(() => {
// Handle PIN on account restoring
if (pin.length === 8) {
restoreByPin(pin);
}
}, [pin]);
return (
<View style={styles.container}>
<Text style={styles.welcomeText}>
<FormattedMessage id="chat.welcome.title" />
</Text>
<View style={styles.subTextWrapper}>
<Text style={styles.subText}>
<FormattedMessage id="chat.welcome.already-joined-title" />
</Text>
<Text style={styles.subText}>
<FormattedMessage id="chat.welcome.already-joined-hint" />
</Text>
</View>
<ChatPinCode
setPin={setPin}
pin={pin}
editable={!isRestoreLoading}
errorMessage={isRestoreFailed ? 'chat.welcome.pin-failed' : ''}
/>
<OrDivider containerStyle={{ paddingVertical: 30 }} />
<View style={styles.buttonsWrapper}>
<ChatsImport />
<ChatAddNewAccount />
</View>
</View>
);
};
export default injectIntl(ChatWelcome);

View File

@ -0,0 +1,71 @@
import React, { useCallback, useRef, useState } from 'react';
import { Text, TextInput, View } from 'react-native';
import { injectIntl } from 'react-intl';
import ActionSheet from 'react-native-actions-sheet';
import { useJoinChat } from '@ecency/ns-query';
import { SquareButton } from '../../../components';
import styles from './chatAddNewAccount.style.ts';
import { ChatPinCode } from './chatPinCode';
const ChatAddNewAccount = ({ intl }) => {
const bottomSheetModalRef = useRef();
const [pin, setPin] = useState('');
const { mutateAsync: joinChat } = useJoinChat();
const onPressCreateAccount = useCallback(() => {
if (pin.length !== 8) {
return;
}
joinChat({ pin });
}, [pin]);
return (
<>
<ActionSheet
ref={bottomSheetModalRef}
gestureEnabled={true}
hideUnderlay
containerStyle={styles.sheetContent}
indicatorStyle={styles.sheetIndicator}
onClose={() => bottomSheetModalRef.current?.hide()}
>
<View style={styles.modal}>
<Text style={styles.title}>{intl.formatMessage({ id: 'chat.create-new-account' })}</Text>
<Text style={styles.subTitle}>
{intl.formatMessage({ id: 'chat.create-description' })}
</Text>
<View style={styles.alertView}>
<Text style={styles.alertText}>
{intl.formatMessage({ id: 'chat.create-pin-description' })}
</Text>
</View>
<ChatPinCode pin={pin} setPin={setPin} />
<View style={styles.buttonsWrapper}>
<SquareButton
text={intl.formatMessage({ id: 'alert.cancel' })}
onPress={() => bottomSheetModalRef.current?.hide()}
style={styles.squareButton}
textStyle={styles.actionText}
/>
<SquareButton
text={intl.formatMessage({ id: 'chat.create-an-account' })}
onPress={onPressCreateAccount}
style={[styles.squareButton, styles.squareButtonInversion]}
textStyle={[styles.actionText, styles.actionTextInversion]}
/>
</View>
</View>
</ActionSheet>
<SquareButton
text={intl.formatMessage({ id: 'chat.create-new-account' })}
onPress={() => bottomSheetModalRef.current?.show()}
style={[styles.squareButton, styles.squareButtonInversion]}
textStyle={[styles.actionText, styles.actionTextInversion]}
/>
</>
);
};
export default injectIntl(ChatAddNewAccount);

View File

@ -0,0 +1,60 @@
import EStyleSheet from 'react-native-extended-stylesheet';
import { TextStyle, ViewStyle } from 'react-native';
export default EStyleSheet.create({
modalView: {} as ViewStyle,
contentContainer: {
paddingTop: 10,
},
sheetContent: {
paddingBottom: 30,
backgroundColor: '$modalBackground',
},
squareButton: {
borderWidth: 1,
borderRadius: 30,
paddingVertical: 8,
paddingHorizontal: 16,
} as ViewStyle,
squareButtonInversion: {
backgroundColor: '$chartBlue',
} as ViewStyle,
actionText: {
fontSize: 16,
alignSelf: 'center',
color: '$chartText',
},
actionTextInversion: {
color: '$white',
},
buttonsWrapper: {
flexDirection: 'row',
justifyContent: 'space-evenly',
marginTop: 50,
} as ViewStyle,
title: {
textAlign: 'center',
fontSize: 24,
fontWeight: '600',
textTransform: 'uppercase',
marginBottom: 20,
paddingHorizontal: 16,
} as TextStyle,
subTitle: {
textAlign: 'left',
fontSize: 16,
paddingHorizontal: 16,
} as TextStyle,
alertView: {
padding: 12,
borderWidth: 1,
borderColor: 'rgb(189 212 247)',
borderRadius: 16,
margin: 16,
marginBottom: 8,
backgroundColor: 'rgb(235 242 252)',
} as ViewStyle,
alertText: {
color: 'rgb(53 124 230)',
} as ViewStyle,
});

View File

@ -0,0 +1,17 @@
import React, { useMemo } from 'react';
import { useJoinedChannelsQuery } from '@ecency/ns-query';
export const ChatChannelsList = React.memo(() => {
const { data: joinedChannels } = useJoinedChannelsQuery();
const data = useMemo(
() => ({
data: [...(joinedChannels ?? [])],
}),
[joinedChannels],
);
console.log({ data });
return <></>;
});

View File

@ -0,0 +1,38 @@
import React from 'react';
import { Keyboard, TextInput, TouchableWithoutFeedback, View, Text } from 'react-native';
import SmoothPinCodeInput from 'react-native-smooth-pincode-input';
import { FormattedMessage } from 'react-intl';
import styles from './chatPinCode.style.ts';
export const ChatPinCode = ({
pin,
setPin,
codeLength = 8,
editable = true,
errorMessage = '',
}) => {
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.container}>
<SmoothPinCodeInput
editable={editable}
codeLength={codeLength}
cellStyle={styles.input}
cellStyleFocused={styles.inputFocus}
value={pin}
onTextChange={setPin}
autoFocus={false}
/>
{errorMessage && (
<Text style={styles.failText}>
<FormattedMessage id={errorMessage} />
</Text>
)}
</View>
</TouchableWithoutFeedback>
);
};

View File

@ -0,0 +1,24 @@
import EStyleSheet from 'react-native-extended-stylesheet';
import { ViewStyle } from 'react-native';
export default EStyleSheet.create({
container: {
alignItems: 'center',
gap: 20,
} as ViewStyle,
input: {
borderRadius: 999,
borderWidth: 1,
borderColor: '$primaryDarkText',
width: 36,
height: 36,
} as ViewStyle,
inputFocus: {
borderWidth: 1,
borderColor: '$primaryBlack',
} as ViewStyle,
failText: {
fontSize: 16,
color: 'red',
},
});

View File

@ -0,0 +1,45 @@
import EStyleSheet from 'react-native-extended-stylesheet';
import { TextStyle, ViewStyle } from 'react-native';
export default EStyleSheet.create({
container: {
alignItems: 'center',
padding: 16,
} as ViewStyle,
subTextWrapper: {
alignItems: 'center',
paddingVertical: 24,
} as ViewStyle,
welcomeText: {
fontSize: 16,
fontWeight: '700',
color: '$primaryBlack',
},
subText: {
fontSize: 16,
fontWeight: '400',
color: '$primaryBlack',
textAlign: 'center',
} as TextStyle,
squareButton: {
borderWidth: 1,
borderRadius: 30,
paddingVertical: 8,
paddingHorizontal: 16,
} as ViewStyle,
squareButtonInversion: {
backgroundColor: '$chartBlue',
} as ViewStyle,
actionText: {
alignSelf: 'center',
color: '$chartText',
},
actionTextInversion: {
color: '$white',
},
buttonsWrapper: {
gap: 10,
flexDirection: 'row',
justifyContent: 'space-evenly',
} as ViewStyle,
});

View File

@ -0,0 +1,77 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Text, TextInput, View } from 'react-native';
import { injectIntl } from 'react-intl';
import { useImportChatByKeys, useRestoreChatByPin } from '@ecency/ns-query';
import ActionSheet from 'react-native-actions-sheet';
import { SquareButton } from '../../../components';
import styles from './chatsImport.style.tsx';
import { TextInputV2 } from '../../../components/textInput/V2/textInputV2.tsx';
import { ChatPinCode } from './chatPinCode';
export const ChatsImport = ({ intl }) => {
const bottomSheetModalRef = useRef();
const [ecencyChatKey, setEcencyChatKey] = useState('');
const [pin, setPin] = useState('');
const { mutateAsync: importChatByKey } = useImportChatByKeys();
const onPressImportChatKey = useCallback(() => {
if (pin.length !== 8 || !ecencyChatKey.length) {
return;
}
importChatByKey({ ecencyChatKey, pin });
}, [ecencyChatKey]);
return (
<>
<ActionSheet
ref={bottomSheetModalRef}
gestureEnabled={true}
hideUnderlay
containerStyle={styles.sheetContent}
indicatorStyle={styles.sheetIndicator}
onClose={() => bottomSheetModalRef.current?.hide()}
>
<View style={styles.modal}>
<Text style={styles.title}>{intl.formatMessage({ id: 'chat.import.title' })}</Text>
<Text style={styles.subTitle}>
{intl.formatMessage({ id: 'chat.import.description' })}
</Text>
<TextInputV2
onChange={setEcencyChatKey}
placeholder={intl.formatMessage({ id: 'chat.key' })}
/>
<View style={styles.alertView}>
<Text style={styles.alertText}>
{intl.formatMessage({ id: 'chat.create-pin-description' })}
</Text>
</View>
<ChatPinCode setPin={setPin} pin={pin} />
<View style={styles.buttonsWrapper}>
<SquareButton
text={intl.formatMessage({ id: 'alert.cancel' })}
onPress={() => bottomSheetModalRef.current?.hide()}
style={styles.squareButton}
textStyle={styles.actionText}
/>
<SquareButton
text={intl.formatMessage({ id: 'chat.import.button' })}
onPress={onPressImportChatKey}
style={[styles.squareButton, styles.squareButtonInversion]}
textStyle={[styles.actionText, styles.actionTextInversion]}
/>
</View>
</View>
</ActionSheet>
<SquareButton
text={intl.formatMessage({ id: 'chat.import.button' })}
onPress={() => bottomSheetModalRef.current?.show()}
style={styles.squareButton}
textStyle={styles.actionText}
/>
</>
);
};
export default injectIntl(ChatsImport);

View File

@ -0,0 +1,67 @@
import EStyleSheet from 'react-native-extended-stylesheet';
import { TextStyle, ViewStyle } from 'react-native';
export default EStyleSheet.create({
input: {
borderWidth: 1,
borderColor: '$borderColor',
paddingVertical: 8,
paddingHorizontal: 16,
marginHorizontal: 20,
borderRadius: 30,
} as ViewStyle,
modalView: {} as ViewStyle,
contentContainer: {
paddingTop: 10,
},
sheetContent: {
paddingBottom: 30,
backgroundColor: '$modalBackground',
},
squareButton: {
borderWidth: 1,
borderRadius: 30,
paddingVertical: 8,
paddingHorizontal: 16,
} as ViewStyle,
squareButtonInversion: {
backgroundColor: '$chartBlue',
} as ViewStyle,
actionText: {
fontSize: 16,
alignSelf: 'center',
color: '$chartText',
},
actionTextInversion: {
color: '$white',
},
buttonsWrapper: {
flexDirection: 'row',
justifyContent: 'space-evenly',
marginTop: 50,
} as ViewStyle,
title: {
textAlign: 'center',
fontSize: 24,
fontWeight: '600',
textTransform: 'uppercase',
marginBottom: 20,
} as TextStyle,
subTitle: {
textAlign: 'center',
fontSize: 16,
marginBottom: 30,
} as TextStyle,
alertView: {
padding: 12,
borderWidth: 1,
borderColor: 'rgb(189 212 247)',
borderRadius: 16,
margin: 16,
marginBottom: 8,
backgroundColor: 'rgb(235 242 252)',
} as ViewStyle,
alertText: {
color: 'rgb(53 124 230)',
} as ViewStyle,
});

View File

@ -0,0 +1,45 @@
import EStyleSheet from 'react-native-extended-stylesheet';
import { TextStyle, ViewStyle } from 'react-native';
export default EStyleSheet.create({
container: {
flex: 1,
backgroundColor: '$primaryLightBackground',
} as ViewStyle,
title: {
fontSize: 14,
alignSelf: 'center',
color: '$primaryDarkText',
fontWeight: 'bold',
} as TextStyle,
view: {
flexGrow: 1,
backgroundColor: '$primaryBackgroundColor',
} as ViewStyle,
channelsTopView: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 12,
paddingHorizontal: 16,
borderBottomWidth: 1,
borderTopWidth: 1,
borderColor: '$borderTopColor',
} as ViewStyle,
inputView: {
paddingVertical: 12,
paddingHorizontal: 16,
borderBottomWidth: 1,
borderColor: '$borderTopColor',
backgroundColor: '$primaryLightBackground',
} as ViewStyle,
input: {
height: 44,
paddingVertical: 8,
paddingHorizontal: 12,
borderWidth: 2,
borderRadius: 24,
borderColor: '$borderTopColor',
backgroundColor: '$primaryBackgroundColor',
} as ViewStyle,
});

View File

@ -0,0 +1,31 @@
import React from 'react';
import { SafeAreaView, View, Text } from 'react-native';
import ScrollableTabView from 'react-native-scrollable-tab-view';
import { injectIntl } from 'react-intl';
import { LoggedInContainer } from '../../../containers';
import { DropdownButton, Header, Notification, TabBar } from '../../../components';
import styles from './chatScreen.style';
import globalStyles from '../../../globalStyles';
const ChatScreen = ({ intl }) => {
return (
<>
<Header />
<SafeAreaView style={styles.container}>
<LoggedInContainer>
{() => (
<View style={styles.view}>
<View style={styles.channelsTopView}>
<Text>Chat</Text>
<DropdownButton isHasChildIcon iconName="more-vert" options={['']} />
</View>
</View>
)}
</LoggedInContainer>
</SafeAreaView>
</>
);
};
export default injectIntl(ChatScreen);

View File

@ -0,0 +1,14 @@
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flex: 1,
backgroundColor: '$primaryLightBackground',
},
view: {},
channelsTopView: {
flexDirection: 'row',
paddingVertical: 12,
paddingHorizontal: 16,
},
});