...
 
Commits (22)
......@@ -25,6 +25,7 @@ import {
Text,
Alert,
Clipboard,
StatusBar,
} from 'react-native';
import FlashMessage from 'react-native-flash-message';
......@@ -64,6 +65,8 @@ import boostedContentService from './src/common/services/boosted-content.service
let deepLinkUrl = '';
const statusBarStyle = Platform.OS === 'ios' ? 'dark-content' : 'default';
// init push service
pushService.init();
......@@ -140,13 +143,10 @@ sessionService.onLogin(async () => {
//on app logout
sessionService.onLogout(() => {
// clear app badge
badgeService.setUnreadConversations(0);
badgeService.setUnreadNotifications(0);
// clear minds settings
mindsService.clear();
// clear offline cache
entitiesStorage.removeAll();
feedsStorage.removeAll();
......@@ -295,6 +295,7 @@ export default class App extends Component<Props, State> {
const app = (
<Provider key="app" {...stores}>
<ErrorBoundary message="An error occurred" containerStyle={CS.centered}>
<StatusBar barStyle={statusBarStyle} />
<NavigationStack
ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
......
import 'react-native';
import React from 'react';
import { Text, TouchableOpacity } from "react-native";
import { shallow } from 'enzyme';
import ReferralCompleteView from '../../../../src/notifications/notification/view/ReferralCompleteView';
import styles from '../../../../src/notifications/notification/style';
// fake data generation
import boostNotificationFactory from '../../../../__mocks__/fake/notifications/BoostNotificationFactory';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
it('renders correctly', () => {
const entity = boostNotificationFactory('referral_complete');
const notification = renderer.create(
<ReferralCompleteView styles={styles} entity={entity}/>
).toJSON();
expect(notification).toMatchSnapshot();
});
\ No newline at end of file
import 'react-native';
import React from 'react';
import { Text, TouchableOpacity } from "react-native";
import { shallow } from 'enzyme';
import ReferralPendingView from '../../../../src/notifications/notification/view/ReferralPendingView';
import styles from '../../../../src/notifications/notification/style';
// fake data generation
import boostNotificationFactory from '../../../../__mocks__/fake/notifications/BoostNotificationFactory';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
it('renders correctly', () => {
const entity = boostNotificationFactory('referral_pending');
const notification = renderer.create(
<ReferralPendingView styles={styles} entity={entity}/>
).toJSON();
expect(notification).toMatchSnapshot();
});
\ No newline at end of file
import 'react-native';
import React from 'react';
import { Text, TouchableOpacity } from "react-native";
import { shallow } from 'enzyme';
import ReferralPingView from '../../../../src/notifications/notification/view/ReferralPingView';
import styles from '../../../../src/notifications/notification/style';
// fake data generation
import boostNotificationFactory from '../../../../__mocks__/fake/notifications/BoostNotificationFactory';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
it('renders correctly', () => {
const entity = boostNotificationFactory('referral_ping');
const notification = renderer.create(
<ReferralPingView styles={styles} entity={entity}/>
).toJSON();
expect(notification).toMatchSnapshot();
});
\ No newline at end of file
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<View
style={
Object {
"flexDirection": "row",
"flexWrap": "wrap",
}
}
>
<Text
onPress={[Function]}
>
You've earned tokens for the completed referral of
<Text
style={
Object {
"color": "#444",
"fontWeight": "bold",
}
}
>
someUser
</Text>
</Text>
</View>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<View
style={
Object {
"flexDirection": "row",
"flexWrap": "wrap",
}
}
>
<Text
onPress={[Function]}
>
You have a pending referral!
<Text
style={
Object {
"color": "#444",
"fontWeight": "bold",
}
}
>
someUser
</Text>
used your referral link when they signed up for Minds. You'll get tokens once they join the rewards program and set up their wallet
</Text>
</View>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly 1`] = `
<View
style={
Object {
"flexDirection": "row",
"flexWrap": "wrap",
}
}
>
<Text
onPress={[Function]}
>
Free tokens are waiting for you! Once you join the rewards program by setting up your Minds wallet, both you and
<Text
style={
Object {
"color": "#444",
"fontWeight": "bold",
}
}
>
someUser
</Text>
will earn tokens for your referral
</Text>
</View>
`;
......@@ -19,9 +19,38 @@ exports[`WithdrawScreen renders correctly 1`] = `
}
}
>
You can request to withdraw your OffChain token rewards to your OnChain address below.
Note: a small amount of ETH will be charged to cover the transaction fee.
Withdrawals may take up to a few hours to complete
You can request to withdraw up to 0 tokens from your rewards to your
<Text
style={
Object {
"fontWeight": "700",
}
}
>
OnChain
</Text>
wallet.
<Text
style={
Object {
"fontSize": 11,
}
}
>
Note: a small amount of ETH will be charged to cover the transaction fee. Withdrawals
<Text
style={
Object {
"fontWeight": "700",
}
}
>
go through an approval process
</Text>
and may take up to 72 hours to complete
</Text>
</Text>
<View
......@@ -128,9 +157,38 @@ exports[`WithdrawScreen renders correctly 1`] = `
}
}
>
You can request to withdraw your OffChain token rewards to your OnChain address below.
Note: a small amount of ETH will be charged to cover the transaction fee.
Withdrawals may take up to a few hours to complete
You can request to withdraw up to 0 tokens from your rewards to your
<Text
style={
Object {
"fontWeight": "700",
}
}
>
OnChain
</Text>
wallet.
<Text
style={
Object {
"fontSize": 11,
}
}
>
Note: a small amount of ETH will be charged to cover the transaction fee. Withdrawals
<Text
style={
Object {
"fontWeight": "700",
}
}
>
go through an approval process
</Text>
and may take up to 72 hours to complete
</Text>
</Text>
<View
......
......@@ -47,7 +47,7 @@ public class MainActivity extends ReactActivity implements OnImagePickerPermissi
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.onCreate(null);
RNBootSplash.show(R.drawable.bootsplash, MainActivity.this);
}
......
const TIME = 10000;
export const waitForElement = async (by, needle) => {
await waitFor(element(by(needle))).toBeVisible().withTimeout(TIME);
}
export const tapElement = async (by, needle) => {
await element(by(needle)).tap();
}
export const typeText = async (by, needle, text) => {
await element(by(needle)).typeText(text);
}
export const waitForAndTap = async (by, needle) => {
await waitForElement(by, needle);
await tapElement(by, needle);
}
export const waitForAndType = async (by, needle, text) => {
await waitForElement(by, needle);
await typeText(by, needle, text);
}
\ No newline at end of file
import sleep from '../src/common/helpers/sleep';
import capturePoster from './actions/capturePoster';
import { waitForElement, waitForAndType, tapElement, waitForAndTap } from './helpers/waitFor';
describe('Login Flow', () => {
const deletePost = async () => {
await waitForAndTap(by.id, 'ActivityMoreButton');
await waitForAndTap(by.id, 'deleteOption');
await waitForAndTap(by.text, 'Ok');
await waitForAndTap(by.text, 'Ok');
}
describe('Post Flow', () => {
beforeEach(async () => {
await device.launchApp({
newInstance: true,
......@@ -17,10 +25,15 @@ describe('Login Flow', () => {
it('should be able to create a text only post', async () => {
const text = 'e2eTest';
await expect(element(by.id('PostInput'))).toBeVisible();
await element(by.id('PostInput')).typeText(text);
await element(by.id('CapturePostButton')).tap();
await waitFor(element(by.id('ActivityMoreButton'))).toBeVisible().withTimeout(5000);
//await element(by.id('ActivityMoreButton')).tap();
// create post
await waitForAndType(by.id, 'PostInput', text);
await tapElement(by.id, 'CapturePostButton');
// wait for newsfeed
await waitForElement(by.id, 'NewsfeedScreen');
await deletePost();
});
});
// created this file because the bundler is not reading index for some reason
import 'react-native-gesture-handler'; // fix ongesture handler error
import "@hawkingnetwork/node-libs-react-native/globals";
import "./global";
import { AppRegistry } from 'react-native';
import App from './App';
import { useScreens } from 'react-native-screens';
useScreens();
// const modules = require.getModules();
// const moduleIds = Object.keys(modules);
// const loadedModuleNames = moduleIds
// .filter(moduleId => modules[moduleId].isInitialized)
// .map(moduleId => modules[moduleId].verboseName);
// const waitingModuleNames = moduleIds
// .filter(moduleId => !modules[moduleId].isInitialized)
// .map(moduleId => modules[moduleId].verboseName);
// // make sure that the modules you expect to be waiting are actually waiting
// console.log(
// 'loaded:',
// loadedModuleNames.length,
// 'waiting:',
// waitingModuleNames.length
// );
// // grab this text blob, and put it in a file named packager/modulePaths.js
// console.log(`module.exports = ${JSON.stringify(loadedModuleNames.sort())};`);
AppRegistry.registerComponent('Minds', () => App);
\ No newline at end of file
// created this file because the bundler is not reading index for some reason
import 'react-native-gesture-handler'; // fix ongesture handler error
import "@hawkingnetwork/node-libs-react-native/globals";
import "./global";
import { AppRegistry } from 'react-native';
import { AppRegistry, Platform } from 'react-native';
import App from './App';
import { useScreens } from 'react-native-screens';
useScreens();
useScreens(Platform.OS !== 'ios');
// const modules = require.getModules();
// const moduleIds = Object.keys(modules);
......
......@@ -22,6 +22,8 @@
<string>3.12.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
......@@ -36,7 +38,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>201907230145</string>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>
......
......@@ -279,7 +279,7 @@ PODS:
- React
- RNReanimated (1.4.0):
- React
- RNScreens (1.0.0-alpha.23):
- RNScreens (2.0.0-alpha.11):
- React
- RNSentry (1.0.9):
- React
......@@ -360,7 +360,7 @@ DEPENDENCIES:
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
https://github.com/cocoapods/specs.git:
trunk:
- boost-for-react-native
- JitsiMeetSDK
- libwebp
......@@ -527,7 +527,7 @@ SPEC CHECKSUMS:
RNGestureHandler: a4ddde1ffc6e590c8127b8b7eabfdade45475c74
RNLocalize: 07eb7a91d10021cdf59d80061ebf3adb8a5b5688
RNReanimated: b2ab0b693dddd2339bd2f300e770f6302d2e960c
RNScreens: f28b48b8345f2f5f39ed6195518291515032a788
RNScreens: ad3661f864ef18d952e9a4799b6791683e33c1fc
RNSentry: 2803ba8c8129dcf26b79e9b4d8c80168be6e4390
RNShare: 8b171d4b43c1d886917fdd303bf7a4b87167b05c
RNSVG: f6177f8d7c095fada7cfee2e4bb7388ba426064c
......@@ -539,4 +539,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 1f47b505eab73a09e6446d8196944df88cfdecc2
COCOAPODS: 1.7.5
COCOAPODS: 1.8.4
......@@ -315,6 +315,9 @@
"errorRemoving":"Error removing comment"
},
"notification":{
"referralPing":"Free tokens are waiting for you! Once you join the rewards program by setting up your Minds wallet, both you and &{user}& will earn tokens for your referral",
"referralPending":"You have a pending referral! &{user}& used your referral link when they signed up for Minds. You'll get tokens once they join the rewards program and set up their wallet",
"referralComplete":"You've earned tokens for the completed referral of &{user}&",
"boostAccepted":"{{count}} tokens &{description}& were accepted.",
"boostCompleted":"{{impressions}}/{{impressions}} views &{description}& have been met.",
"boostGiftView":"{{name}} gifted you {{impressions}} views &{description}&",
......@@ -588,7 +591,9 @@
"errorReadingStatus":"Error reading withdrawal status",
"errorOnlyOnceDay":"You can only withdraw once a day",
"errorWithdrawing":"Error withdrawing tokens",
"youCanRequest":"You can request to withdraw your OffChain token rewards to your OnChain address below.\n Note: a small amount of ETH will be charged to cover the transaction fee.\n Withdrawals may take up to a few hours to complete",
"youCanRequest1":"You can request to withdraw up to {{amount}} tokens from your rewards to your &{onchain}& wallet.\n &{note}&",
"youCanRequest2":"Note: a small amount of ETH will be charged to cover the transaction fee. Withdrawals &{approval}& and may take up to 72 hours to complete",
"youCanRequest3":"go through an approval process",
"holdingMessage":"{{amount}} tokens are unavailable due to credit card payment. They will be released after 30 days the payment occurred.",
"amount":"Amount",
"errorReadingBalances":"Error reading balances",
......
......@@ -506,7 +506,9 @@
"errorReadingStatus": "Error leyendo el estado del retiro",
"errorOnlyOnceDay": "Tu puedes retirar solo una vez por día",
"errorWithdrawing": "Error retirando tokens",
"youCanRequest": "Puede solicitar retirar sus recompensas de token de OffChain a su dirección de OnChain a continuación.\n Nota: se cobrará una pequeña cantidad de ETH para cubrir la tarifa de la transacción.\n Los retiros pueden tardar hasta unas pocas horas en completarse.",
"youCanRequest1":"Puedes solicitar retirar hasta {{amount}} tokens de tus recomensas a tu dirección de &{onchain}&.\n &{note}&",
"youCanRequest2":"Nota: se cobrará una pequeña cantidad de ETH para cubrir la tarifa de la transacción. Los retiros &{approval}& y pueden tardar hasta 72 horas en completarse",
"youCanRequest3":"pasan por un proceso de aprobación",
"holdingMessage": "{{amount}} tokens no están disponibles debido al pago con tarjeta de crédito. Serán liberados después de 30 días de ocurrido el pago.",
"amount": "Monto",
"errorReadingBalances": "Error leyendo saldos",
......
......@@ -55,7 +55,6 @@ export default class LoginForm extends Component {
* Render
*/
render() {
console.log('IST',Platform.isTesting);
const msg = this.state.msg ? (
<Animatable.Text animation="bounceInLeft" style={[CommonStyle.colorLight, { textAlign: 'center' }]} testID="loginMsg">{this.state.msg}</Animatable.Text>
) : null;
......
......@@ -38,7 +38,7 @@ export default class ActivityActionSheet extends Component {
*/
constructor(props) {
super(props);
this.deleteOption = <Text style={[CS.colorDanger, CS.fontXL]}>{i18n.t('delete')}</Text>
this.deleteOption = <Text testID='deleteOption' style={[CS.colorDanger, CS.fontXL]}>{i18n.t('delete')}</Text>
}
/**
......
......@@ -45,12 +45,15 @@ import WelcomePointsView from './view/WelcomePointsView';
import WireHappenedView from './view/WireHappenedView';
import ReportActionedView from './view/ReportActionedView';
import MessengerInviteView from './view/MessengerInviteView';
import RewardsStateIncreaseView from './view/RewardsStateIncreaseView';
import RewardsStateDecreaseView from './view/RewardsStateDecreaseView';
import RewardsStateDecreaseTodayView from './view/RewardStateDecreaseTodayView';
import RewardsSummaryView from './view/RewardsSummaryView';
import ReferralCompleteView from './view/ReferralCompleteView';
import ReferralPendingView from './view/ReferralPendingView';
import ReferralPingView from './view/ReferralPingView';
import styles from './style';
import RewardsStateIncreaseView from "./view/RewardsStateIncreaseView";
import RewardsStateDecreaseView from "./view/RewardsStateDecreaseView";
import RewardsStateDecreaseTodayView from "./view/RewardStateDecreaseTodayView";
import RewardsSummaryView from "./view/RewardsSummaryView";
/**
* Main Notification row Component
......@@ -194,6 +197,15 @@ export default class Notification extends Component {
case "wire_happened":
return <WireHappenedView entity={entity} navigation={this.props.navigation} styles={styles} />
case "referral_complete":
return <ReferralCompleteView entity={entity} navigation={this.props.navigation} styles={styles} />
case "referral_pending":
return <ReferralPendingView entity={entity} navigation={this.props.navigation} styles={styles} />
case "referral_ping":
return <ReferralPingView entity={entity} navigation={this.props.navigation} styles={styles} />
case "report_actioned":
return <ReportActionedView entity={entity} navigation={this.props.navigation} styles={styles} />
......
import React, {
PureComponent
} from 'react';
import {
Text,
View,
} from 'react-native';
import i18n from '../../../common/services/i18n.service';
/**
* Referral Complete
*/
export default class ReferralCompleteView extends PureComponent {
/**
* Navigate to navToContributions
*/
navToContributions = () => {
this.props.navigation.push('Contributions');
};
/**
* Render
*/
render() {
const styles = this.props.styles;
return (
<View style={styles.bodyContents}>
<Text onPress={this.navToContributions}>
{i18n.to('notification.referralComplete', null, {
user: (
<Text style={styles.link}>{this.props.entity.fromObj.name}</Text>
),
})}
</Text>
</View>
);
}
}
import React, {
PureComponent
} from 'react';
import {
Text,
View,
} from 'react-native';
import i18n from '../../../common/services/i18n.service';
/**
* Referral Pending
*/
export default class ReferralPendingView extends PureComponent {
/**
* Navigate to navToContributions
*/
navToContributions = () => {
this.props.navigation.push('Contributions');
};
/**
* Render
*/
render() {
const styles = this.props.styles;
return (
<View style={styles.bodyContents}>
<Text onPress={this.navToContributions}>
{i18n.to('notification.referralPending', null, {
user: (
<Text style={styles.link}>{this.props.entity.fromObj.name}</Text>
),
})}
</Text>
</View>
);
}
}
import React, {
PureComponent
} from 'react';
import {
Text,
View,
} from 'react-native';
import i18n from '../../../common/services/i18n.service';
/**
* Referral Ping
*/
export default class ReferralPingView extends PureComponent {
/**
* Navigate to navToContributions
*/
navToContributions = () => {
this.props.navigation.push('Contributions');
};
/**
* Render
*/
render() {
const styles = this.props.styles;
return (
<View style={styles.bodyContents}>
<Text onPress={this.navToContributions}>
{i18n.to('notification.referralPing', null, {
user: (
<Text style={styles.link}>{this.props.entity.fromObj.name}</Text>
),
})}
</Text>
</View>
);
}
}
......@@ -30,6 +30,7 @@ import WelcomeStep from './steps/WelcomeStep';
import { CommonStyle as CS } from '../styles/Common';
import navigationService from '../navigation/NavigationService';
import i18nService from '../common/services/i18n.service';
import CenteredLoading from '../common/components/CenteredLoading';
@observer
@inject('onboarding', 'hashtag')
......@@ -59,6 +60,9 @@ export default class OnboardingScreen extends Component {
render() {
const steps = [];
if (!this.props.onboarding.progress) {
return <CenteredLoading/>
}
const completed_items = this.props.onboarding.progress.completed_items;
// if (!completed_items.some(r => r == 'creator_frequency')) {
......
......@@ -33,7 +33,7 @@ class OnboardingService {
* Get suggested users
*/
getSuggestedUsers() {
return api.get('api/v2/suggestions', {limit: 12});
return api.get('api/v2/suggestions/user', {limit: 12});
}
}
......
......@@ -25,8 +25,14 @@ class OnboardingStore {
}
async getSuggestedUsers() {
const users = await onboardingService.getSuggestedUsers();
if (users.suggestions) this.suggestedUsers.list.setList({entities: users.suggestions.map(r => UserModel.create(r.entity))});
try {
const users = await onboardingService.getSuggestedUsers();
if (users.suggestions) {
this.suggestedUsers.list.setList({entities: users.suggestions.map(r => UserModel.create(r.entity))});
}
} catch (err) {
console.log(err);
}
}
/**
......
......@@ -17,15 +17,14 @@ import i18n from '../../common/services/i18n.service';
@observer
export default class SuggestedChannelsStep extends Component {
componentWillMount() {
componentDidMount() {
this.props.onboarding.suggestedUsers.list.clearList();
this.props.onboarding.getSuggestedUsers();
}
renderUser = (user) => {
return <DiscoveryUser
store={this.props.onboarding.suggestedUsers}
entity={{item: user}}
row={{item: user}}
key={user.guid}
/>
}
......
......@@ -28,6 +28,7 @@ import formatDate from '../../common/helpers/date';
import token from '../../common/helpers/token';
import readableError from '../../common/helpers/readable-error';
import i18n from '../../common/services/i18n.service';
import { CommonStyle } from '../../styles/Common';
@inject('user', 'withdraw')
@observer
......@@ -162,7 +163,26 @@ export default class WithdrawScreen extends Component {
return (
<View style={style.formWrapperView}>
<Text style={style.legendText}>
{i18n.t('wallet.withdraw.youCanRequest')}
{
i18n.to(
'wallet.withdraw.youCanRequest1',
{
amount: this.getAmount()
},
{
onchain: <Text style={CommonStyle.bold}>OnChain</Text>,
note: <Text style={{fontSize: 11}}>
{i18n.to(
'wallet.withdraw.youCanRequest2',
null,
{
approval: <Text style={CommonStyle.bold}>{i18n.t('wallet.withdraw.youCanRequest3')}</Text>
},
)}
</Text>,
}
)
}
{
!!this.state.withholding ?
i18n.t('wallet.withdraw.holdingMessage',{amount: number(this.state.withholding, 0, 4)}) : ''
......
......@@ -8797,13 +8797,20 @@ [email protected]^0.14.1, [email protected]^0.14.6:
dependencies:
hoist-non-react-statics "^2.3.1"
"[email protected]^1.0.0 || ^1.0.0-alpha", [email protected]^1.0.0-alpha.23:
"[email protected]^1.0.0 || ^1.0.0-alpha":
version "1.0.0-alpha.23"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-1.0.0-alpha.23.tgz#25d7ea4d11bda4fcde2d1da7ae50271c6aa636e0"
integrity sha512-tOxHGQUN83MTmQB4ghoQkibqOdGiX4JQEmeyEv96MKWO/x8T2PJv84ECUos9hD3blPRQwVwSpAid1PPPhrVEaw==
dependencies:
debounce "^1.2.0"
[email protected]^2.0.0-alpha.11:
version "2.0.0-alpha.11"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.0.0-alpha.11.tgz#077674284e0f80130cf971ba8eacc4f969724eea"
integrity sha512-Sw01mMTvqMgNl4stk7rdcE8LRiISTx7DhXMeBgvmlI4uF1rIZBFcTV5tH/wZ8ld6Pa/H5ASKWAiaaMMxgv1fBw==
dependencies:
debounce "^1.2.0"
[email protected]^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/react-native-scrollable-mixin/-/react-native-scrollable-mixin-1.0.1.tgz#34a32167b64248594154fd0d6a8b03f22740548e"
......