diff --git a/globals.js b/globals.js new file mode 100644 index 000000000..5bc2bc43b --- /dev/null +++ b/globals.js @@ -0,0 +1 @@ +global.TextEncoder = require('text-encoding').TextEncoder; diff --git a/src/components/textInput/V2/textInputV2.style.tsx b/src/components/textInput/V2/textInputV2.style.tsx new file mode 100644 index 000000000..a401258ac --- /dev/null +++ b/src/components/textInput/V2/textInputV2.style.tsx @@ -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, +}); diff --git a/src/components/textInput/V2/textInputV2.tsx b/src/components/textInput/V2/textInputV2.tsx new file mode 100644 index 000000000..c53082626 --- /dev/null +++ b/src/components/textInput/V2/textInputV2.tsx @@ -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(parentValue || ''); + + useEffect(() => { + parentOnChange(value); + }, [value]); + + return ; +}; diff --git a/src/screens/chat/components/ChatWelcome.tsx b/src/screens/chat/components/ChatWelcome.tsx new file mode 100644 index 000000000..5cf67f61a --- /dev/null +++ b/src/screens/chat/components/ChatWelcome.tsx @@ -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 ( + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default injectIntl(ChatWelcome); diff --git a/src/screens/chat/components/chatAddNewAccount.jsx b/src/screens/chat/components/chatAddNewAccount.jsx new file mode 100644 index 000000000..11dc03d9f --- /dev/null +++ b/src/screens/chat/components/chatAddNewAccount.jsx @@ -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 ( + <> + bottomSheetModalRef.current?.hide()} + > + + {intl.formatMessage({ id: 'chat.create-new-account' })} + + {intl.formatMessage({ id: 'chat.create-description' })} + + + + {intl.formatMessage({ id: 'chat.create-pin-description' })} + + + + + bottomSheetModalRef.current?.hide()} + style={styles.squareButton} + textStyle={styles.actionText} + /> + + + + + bottomSheetModalRef.current?.show()} + style={[styles.squareButton, styles.squareButtonInversion]} + textStyle={[styles.actionText, styles.actionTextInversion]} + /> + + ); +}; + +export default injectIntl(ChatAddNewAccount); diff --git a/src/screens/chat/components/chatAddNewAccount.style.ts b/src/screens/chat/components/chatAddNewAccount.style.ts new file mode 100644 index 000000000..5ff594e27 --- /dev/null +++ b/src/screens/chat/components/chatAddNewAccount.style.ts @@ -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, +}); diff --git a/src/screens/chat/components/chatChannelsList.tsx b/src/screens/chat/components/chatChannelsList.tsx new file mode 100644 index 000000000..4bd3969c2 --- /dev/null +++ b/src/screens/chat/components/chatChannelsList.tsx @@ -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 <>; +}); diff --git a/src/screens/chat/components/chatPinCode.jsx b/src/screens/chat/components/chatPinCode.jsx new file mode 100644 index 000000000..9305a6fe6 --- /dev/null +++ b/src/screens/chat/components/chatPinCode.jsx @@ -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 ( + { + Keyboard.dismiss(); + }} + > + + + {errorMessage && ( + + + + )} + + + ); +}; diff --git a/src/screens/chat/components/chatPinCode.style.ts b/src/screens/chat/components/chatPinCode.style.ts new file mode 100644 index 000000000..2376eb400 --- /dev/null +++ b/src/screens/chat/components/chatPinCode.style.ts @@ -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', + }, +}); diff --git a/src/screens/chat/components/chatWelcome.style.ts b/src/screens/chat/components/chatWelcome.style.ts new file mode 100644 index 000000000..d0f0a866b --- /dev/null +++ b/src/screens/chat/components/chatWelcome.style.ts @@ -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, +}); diff --git a/src/screens/chat/components/chatsImport.jsx b/src/screens/chat/components/chatsImport.jsx new file mode 100644 index 000000000..4daaec66d --- /dev/null +++ b/src/screens/chat/components/chatsImport.jsx @@ -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 ( + <> + bottomSheetModalRef.current?.hide()} + > + + {intl.formatMessage({ id: 'chat.import.title' })} + + {intl.formatMessage({ id: 'chat.import.description' })} + + + + + {intl.formatMessage({ id: 'chat.create-pin-description' })} + + + + + bottomSheetModalRef.current?.hide()} + style={styles.squareButton} + textStyle={styles.actionText} + /> + + + + + bottomSheetModalRef.current?.show()} + style={styles.squareButton} + textStyle={styles.actionText} + /> + + ); +}; + +export default injectIntl(ChatsImport); diff --git a/src/screens/chat/components/chatsImport.style.tsx b/src/screens/chat/components/chatsImport.style.tsx new file mode 100644 index 000000000..cc684baf2 --- /dev/null +++ b/src/screens/chat/components/chatsImport.style.tsx @@ -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, +}); diff --git a/src/screens/chat/screen/channelsScreen.style.ts b/src/screens/chat/screen/channelsScreen.style.ts new file mode 100644 index 000000000..08cf0d038 --- /dev/null +++ b/src/screens/chat/screen/channelsScreen.style.ts @@ -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, +}); diff --git a/src/screens/chat/screen/chatScreen.js b/src/screens/chat/screen/chatScreen.js new file mode 100644 index 000000000..99090e8c3 --- /dev/null +++ b/src/screens/chat/screen/chatScreen.js @@ -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 ( + <> +
+ + + {() => ( + + + Chat + + + + )} + + + + ); +}; + +export default injectIntl(ChatScreen); diff --git a/src/screens/chat/screen/chatScreen.style.js b/src/screens/chat/screen/chatScreen.style.js new file mode 100644 index 000000000..77063f925 --- /dev/null +++ b/src/screens/chat/screen/chatScreen.style.js @@ -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, + }, +});