Skip to content
Commits on Source (23)
......@@ -72,4 +72,4 @@ untyped-import
untyped-type-import
[version]
^0.105.0
\ No newline at end of file
^0.107.0
......@@ -59,6 +59,7 @@ import sqliteStorageProviderService from './src/common/services/sqlite-storage-p
import commentStorageService from './src/comments/CommentStorageService';
import * as Sentry from '@sentry/react-native';
import apiService from './src/common/services/api.service';
import boostedContentService from './src/common/services/boosted-content.service';
let deepLinkUrl = '';
......@@ -81,7 +82,7 @@ sessionService.onLogin(async () => {
logService.info('[App] Getting minds settings and onboarding progress');
// load minds settings and onboarding progresss on login
const results = await Promise.all([mindsService.getSettings(), stores.onboarding.getProgress()]);
const results = await Promise.all([mindsService.getSettings(), stores.onboarding.getProgress(), boostedContentService.load()]);
logService.info('[App] updatting features');
// reload fatures on login
......
......@@ -12,12 +12,13 @@ import logService from './src/common/services/log.service';
import * as Sentry from '@sentry/react-native';
import { isAbort, isNetworkFail } from './src/common/helpers/abortableFetch';
import { isApiError } from './src/common/services/api.service';
import { isUserError } from './src/common/UserError';
// Init Sentry (if not running test)
if (process.env.JEST_WORKER_ID === undefined) {
Sentry.init({
dsn: 'https://d650fc58f2da4dc8ae9d95847bce152d@sentry.io/1538735',
dsn: 'https://16c9b543563140a0936cc3cd3714481d@sentry.io/1766867',
ignoreErrors: [
'Non-Error exception captured with keys: code, domain, localizedDescription', // ignore initial error of sdk
],
......@@ -33,6 +34,10 @@ if (process.env.JEST_WORKER_ID === undefined) {
if (isAbort(hint.originalException)) {
return null;
}
// ignore user errors
if (isUserError(hint.originalException)) {
return null;
}
// only log api 500 errors
if (isApiError(hint.originalException) && hint.originalException.status < 500) {
return null;
......
......@@ -722,6 +722,9 @@ exports[`channel subscribers component should render correctly 1`] = `
"metadataService": null,
"offset": "",
"refreshing": false,
"viewed": Viewed {
"viewed": Map {},
},
},
"loadList": [MockFunction],
"refresh": [MockFunction],
......@@ -1096,6 +1099,9 @@ exports[`channel subscribers component should render correctly 1`] = `
"metadataService": null,
"offset": "",
"refreshing": false,
"viewed": Viewed {
"viewed": Map {},
},
},
"loadList": [MockFunction],
"refresh": [MockFunction],
......@@ -1470,6 +1476,9 @@ exports[`channel subscribers component should render correctly 1`] = `
"metadataService": null,
"offset": "",
"refreshing": false,
"viewed": Viewed {
"viewed": Map {},
},
},
"loadList": [MockFunction],
"refresh": [MockFunction],
......
......@@ -29,7 +29,7 @@ systemProp.org.gradle.internal.http.socketTimeout=180000
versionName=3.11.0
# CUSTOM
versionCode=1050000015
versionCode=1050000016
# PLAY STORE
# versionCode=310033
# versionCode=310034
......@@ -418,7 +418,7 @@ export default class BoostScreen extends Component {
if (this.state.type !== 'p2p') {
switch (this.state.payment) {
case 'tokens':
let payload = await BlockchainWalletService.selectCurrent(i18n.t('boosts.selectWalletNetworkMessage'), { signable: true, offchain: true, buyable: true });
let payload = await BlockchainWalletService.selectCurrent(i18n.t('boosts.selectWalletNetworkMessage'), { signable: true, offchain: true, buyable: true, currency: 'tokens' });
if (!payload || payload.cancelled) {
return;
......@@ -478,7 +478,7 @@ export default class BoostScreen extends Component {
switch (this.state.payment) {
case 'tokens':
let payload = await BlockchainWalletService.selectCurrent(i18n.t('boosts.selectWalletChannelMessage'), { signable: true, offchain: true, buyable: true });
let payload = await BlockchainWalletService.selectCurrent(i18n.t('boosts.selectWalletChannelMessage'), { signable: true, offchain: true, buyable: true, currency: 'tokens' });
if (!payload || payload.cancelled) {
return;
......
......@@ -182,7 +182,7 @@ export default class CapturePoster extends Component {
placeholderTextColor='#ccc'
underlineColorAndroid='transparent'
onChangeText={this.setText}
value={this.state.text}
value={this.props.capture.text}
multiline={true}
selectTextOnFocus={false}
onSelectionChange={this.onSelectionChanges}
......
......@@ -5,6 +5,7 @@ import {
import OffsetListStore from '../../common/stores/OffsetListStore';
import channelService from '../ChannelService';
import UserModel from '../UserModel';
/**
* Subscribers Store
......@@ -38,6 +39,7 @@ class ChannelSubscribersStore {
return channelService.getSubscribers(this.guid, this.filter, this.list.offset)
.then( feed => {
feed.entities = UserModel.createMany(feed.entities);
this.list.setList(feed);
})
.finally(() => {
......
import {
Alert,
} from 'react-native';
export class UserError extends Error {
constructor(...args) {
super(...args)
Alert.alert(
'',
`
${args[0]}
`,
[{
text: 'Ok',
}]
);
}
}
export const isUserError = function(err) {
return err instanceof UserError;
}
// @flow
import FeedsService from "./feeds.service";
import sessionService from "./session.service";
import logService from "./log.service";
// types
import type ActivityModel from "../../newsfeed/ActivityModel";
......@@ -16,26 +16,22 @@ class BoostedContentService {
boosts: Array<ActivityModel> = [];
/**
* Constructor
*/
constructor() {
// always reload on login or app restart
sessionService.onLogin(this.load);
}
/**
* Reload boosts list
*/
load = async(): Promise<any> => {
await this.feedsService
.setLimit(12)
.setOffset(0)
.setPaginated(false)
.setEndpoint('api/v2/boost/feed')
.fetchRemoteOrLocal();
this.boosts = await this.feedsService.getEntities();
try {
await this.feedsService
.setLimit(12)
.setOffset(0)
.setPaginated(false)
.setEndpoint('api/v2/boost/feed')
.fetchRemoteOrLocal();
this.boosts = await this.feedsService.getEntities();
} catch (err) {
logService.exception('[BoostedContentService]', err);
}
}
/**
......
......@@ -224,11 +224,11 @@ class EntitiesService {
* @param {Object} entity
*/
cleanEntity(entity: Object) {
if (entity['thumbs:up:user_guids']) {
if (entity['thumbs:up:user_guids'] && Array.isArray(entity['thumbs:up:user_guids'])) {
entity['thumbs:up:user_guids'] = entity['thumbs:up:user_guids'].filter((guid: string): boolean => guid == sessionService.guid);
}
if (entity['thumbs:down:user_guids']) {
if (entity['thumbs:down:user_guids'] && Array.isArray(entity['thumbs:down:user_guids'])) {
entity['thumbs:down:user_guids'] = entity['thumbs:down:user_guids'].filter((guid: string): boolean => guid == sessionService.guid);
}
}
......
......@@ -8,6 +8,7 @@ import settingsStore from '../../settings/SettingsStore';
import * as Sentry from '@sentry/react-native';
import { isNetworkFail } from '../helpers/abortableFetch';
import { ApiError } from './api.service';
import { isUserError } from '../UserError';
const parseErrorStack = error => {
if (!error || !error.stack) {
......@@ -76,7 +77,7 @@ class LogService {
prepend = null;
}
if (!isNetworkFail(error) && (!this.isApiError(error) || this.isUnexpectedError(error))) {
if (!isNetworkFail(error) && !isUserError(error) && (!this.isApiError(error) || this.isUnexpectedError(error))) {
// report the issue to sentry
Sentry.captureException(error);
}
......
import api from './../../common/services/api.service';
import logService from './log.service';
import i18n from './i18n.service';
import { UserError } from '../UserError';
export function vote(guid, direction, data) {
return api.put('api/v1/votes/' + guid + '/' + direction, data)
......@@ -9,6 +10,6 @@ export function vote(guid, direction, data) {
})
.catch(err => {
logService.exception('[VotesService]', err);
throw new Error(i18n.t('errorMessage'));
throw new UserError(i18n.t('errorMessage'));
})
}
......@@ -3,6 +3,7 @@ import channelService from '../../channel/ChannelService';
import { revokeBoost, rejectBoost, acceptBoost} from '../../boost/BoostService';
import logService from '../services/log.service';
import metadataService from '../services/metadata.service';
import Viewed from './Viewed';
/**
* Common infinite scroll list
......@@ -34,6 +35,11 @@ export default class OffsetListStore {
*/
metadataService = null;
/**
* Viewed store
*/
viewed = new Viewed;
/**
* Constructor
* @param {string} type 'shallow'|'ref'|null
......
......@@ -39,7 +39,7 @@ export default class DiscoveryUser extends Component {
_navToChannel = () => {
Keyboard.dismiss();
if (this.props.navigation) {
this.props.navigation.push('Channel', { entity: this.props.entity.item });
this.props.navigation.push('Channel', { guid: this.props.entity.item.guid });
}
}
......
......@@ -52,7 +52,7 @@ export default class MessengerScreen extends Component {
/**
* On component will mount
*/
componentWillMount() {
componentDidMount() {
this.props.messengerList.loadList();
......
......@@ -19,6 +19,7 @@ import CenteredLoading from '../common/components/CenteredLoading';
import commentsStoreProvider from '../comments/CommentsStoreProvider';
import logService from '../common/services/log.service';
import i18n from '../common/services/i18n.service';
import OffsetFeedListStore from '../common/stores/OffsetFeedListStore';
/**
* Activity screen
......@@ -61,10 +62,15 @@ export default class ActivityScreen extends Component {
}
if (params.entity && params.entity._list) {
params.entity._list.viewed.addViewed(
params.entity,
params.entity._list.metadataService
);
// this second condition it's for legacy boost feed
if (params.entity._list instanceof OffsetFeedListStore) {
params.entity._list.addViewed(params.entity);
} else {
params.entity._list.viewed.addViewed(
params.entity,
params.entity._list.metadataService
);
}
}
}
......
......@@ -54,7 +54,7 @@ export default class NotificationsScreen extends Component {
/**
* On component mount
*/
componentWillMount() {
componentDidMount() {
this.disposeEnter = this.props.navigation.addListener('didFocus', (s) => {
// ignore back navigation
if (s.action.type === 'Navigation/NAVIGATE' && s.action.routeName === 'Notifications') {
......@@ -146,7 +146,7 @@ export default class NotificationsScreen extends Component {
stickyHeaderIndices={[0]}
windowSize={8}
refreshing={list.refreshing}
style={CS.backgroundWhite}
style={[CS.backgroundWhite, CS.flexContainer]}
/>
);
......
......@@ -18,6 +18,7 @@ import sessionService from '../../common/services/session.service';
import imagePicker from '../../common/services/image-picker.service';
import withPreventDoubleTap from '../../common/components/PreventDoubleTap';
import i18n from '../../common/services/i18n.service';
import { UserError } from '../../common/UserError';
const TouchableCustom = withPreventDoubleTap(TouchableOpacity);
......@@ -72,7 +73,7 @@ export default class ChannelSetupStep extends Component {
}
save = async () => {
if (this.store.isUploading) throw Error('Avatar is uploading, please wait');
if (this.store.isUploading) throw new UserError('Avatar is uploading, please wait');
if (!this.state.dirty) return;
payload = {
briefdescription: this.state.briefdescription,
......