Unverified Commit 7dffa14b authored by Djorkaeff Alexandre's avatar Djorkaeff Alexandre Committed by GitHub
Browse files

[NEW] Request review (#1627)

parent b6e48e37
......@@ -103,7 +103,7 @@ Readme will guide you on how to config.
| Custom Fields on Signup | ✅ |
| Report message | ✅ |
| Theming | ✅ |
| Settings -> Review the App | |
| Settings -> Review the App | |
| Settings -> Default Browser | ❌ |
| Admin panel | ✅ |
| Reply message from notification | ✅ |
......
export const PLAY_MARKET_LINK = 'https://play.google.com/store/apps/details?id=chat.rocket.reactnative';
export const APP_STORE_LINK = 'https://itunes.apple.com/app/rocket-chat-experimental/id1272915472?ls=1&mt=8';
import { getBundleId, isIOS } from '../utils/deviceInfo';
const APP_STORE_ID = '1272915472';
export const PLAY_MARKET_LINK = `market://details?id=${ getBundleId }`;
export const APP_STORE_LINK = `itms-apps://itunes.apple.com/app/id${ APP_STORE_ID }`;
export const LICENSE_LINK = 'https://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/LICENSE';
export const STORE_REVIEW_LINK = isIOS ? `${ APP_STORE_LINK }?action=write-review` : PLAY_MARKET_LINK;
......@@ -42,6 +42,7 @@ import {
MENTIONS_TRACKING_TYPE_USERS
} from './constants';
import CommandsPreview from './CommandsPreview';
import { Review } from '../../utils/review';
const imagePickerConfig = {
cropping: true,
......@@ -506,6 +507,7 @@ class MessageBox extends Component {
};
try {
await RocketChat.sendFileMessage(rid, fileInfo, tmid, server, user);
Review.pushPositiveEvent();
} catch (e) {
log(e);
}
......
......@@ -332,6 +332,13 @@ export default {
Reset_password: 'Reset password',
resetting_password: 'resetting password',
RESET: 'RESET',
Review_app_title: 'Are you enjoying this app?',
Review_app_desc: 'Give us 5 stars on {{store}}',
Review_app_yes: 'Sure!',
Review_app_no: 'No',
Review_app_later: 'Maybe later',
Review_app_unable_store: 'Unable to open {{store}}',
Review_this_app: 'Review this app',
Roles: 'Roles',
Room_actions: 'Room actions',
Room_changed_announcement: 'Room announcement changed to: {{announcement}} by {{userBy}}',
......
......@@ -302,6 +302,13 @@ export default {
Reset_password: 'Resetar senha',
resetting_password: 'redefinindo senha',
RESET: 'RESETAR',
Review_app_title: 'Você está gostando do app?',
Review_app_desc: 'Nos dê 5 estrelas na {{store}}',
Review_app_yes: 'Claro!',
Review_app_no: 'Não',
Review_app_later: 'Talvez depois',
Review_app_unable_store: 'Não foi possível abrir {{store}}',
Review_this_app: 'Avaliar esse app',
Roles: 'Papéis',
Room_actions: 'Ações',
Room_changed_announcement: 'O anúncio da sala foi alterado para: {{announcement}} por {{userBy}}',
......
import { Alert, Linking, AsyncStorage } from 'react-native';
import { isIOS } from './deviceInfo';
import I18n from '../i18n';
import { showErrorAlert } from './info';
import { STORE_REVIEW_LINK } from '../constants/links';
const store = isIOS ? 'App Store' : 'Play Store';
const reviewKey = 'reviewKey';
const reviewDelay = 2000;
const numberOfDays = 7;
const numberOfPositiveEvent = 5;
const daysBetween = (date1, date2) => {
const one_day = 1000 * 60 * 60 * 24;
const date1_ms = date1.getTime();
const date2_ms = date2.getTime();
const difference_ms = date2_ms - date1_ms;
return Math.round(difference_ms / one_day);
};
const onCancelPress = () => {
try {
const data = JSON.stringify({ doneReview: true });
return AsyncStorage.setItem(reviewKey, data);
} catch (e) {
// do nothing
}
};
export const onReviewPress = async() => {
await onCancelPress();
try {
const supported = await Linking.canOpenURL(STORE_REVIEW_LINK);
if (supported) {
Linking.openURL(STORE_REVIEW_LINK);
}
} catch (e) {
showErrorAlert(I18n.t('Review_app_unable_store', { store }));
}
};
const onAskMeLaterPress = () => {
try {
const data = JSON.stringify({ lastReview: new Date().getTime() });
return AsyncStorage.setItem(reviewKey, data);
} catch (e) {
// do nothing
}
};
const onReviewButton = { text: I18n.t('Review_app_yes'), onPress: onReviewPress };
const onAskMeLaterButton = { text: I18n.t('Review_app_later'), onPress: onAskMeLaterPress };
const onCancelButton = { text: I18n.t('Review_app_no'), onPress: onCancelPress };
const askReview = () => Alert.alert(
I18n.t('Review_app_title'),
I18n.t('Review_app_desc', { store }),
isIOS
? [onReviewButton, onAskMeLaterButton, onCancelButton]
: [onAskMeLaterButton, onCancelButton, onReviewButton],
{
cancelable: true,
onDismiss: onAskMeLaterPress
}
);
const tryReview = async() => {
const data = await AsyncStorage.getItem(reviewKey) || '{}';
const reviewData = JSON.parse(data);
const { lastReview = 0, doneReview = false } = reviewData;
const lastReviewDate = new Date(lastReview);
// if ask me later was pressed earlier, we can ask for review only after {{numberOfDays}} days
// if there's no review and it wasn't dismissed by the user
if (daysBetween(lastReviewDate, new Date()) >= numberOfDays && !doneReview) {
setTimeout(askReview, reviewDelay);
}
};
class ReviewApp {
positiveEventCount = 0;
pushPositiveEvent = () => {
if (this.positiveEventCount >= numberOfPositiveEvent) {
return;
}
this.positiveEventCount += 1;
if (this.positiveEventCount === numberOfPositiveEvent) {
tryReview();
}
}
}
export const Review = new ReviewApp();
......@@ -22,6 +22,7 @@ import StatusBar from '../containers/StatusBar';
import { SWITCH_TRACK_COLOR, themes } from '../constants/colors';
import { withTheme } from '../theme';
import { themedHeader } from '../utils/navigation';
import { Review } from '../utils/review';
const styles = StyleSheet.create({
container: {
......@@ -201,6 +202,8 @@ class CreateChannelView extends React.Component {
create({
name: channelName, users, type, readOnly, broadcast
});
Review.pushPositiveEvent();
}
removeUser = (user) => {
......
......@@ -47,6 +47,7 @@ import {
handleCommandReplyLatest
} from '../../commands';
import ModalNavigation from '../../lib/ModalNavigation';
import { Review } from '../../utils/review';
const stateAttrsUpdate = [
'joined',
......@@ -472,6 +473,7 @@ class RoomView extends React.Component {
try {
await RocketChat.setReaction(shortname, messageId);
this.onReactionClose();
Review.pushPositiveEvent();
} catch (e) {
log(e);
}
......@@ -556,6 +558,7 @@ class RoomView extends React.Component {
this.list.current.update();
}
this.setLastOpen(null);
Review.pushPositiveEvent();
});
};
......
......@@ -33,6 +33,7 @@ import { withSplit } from '../../split';
import Navigation from '../../lib/Navigation';
import { LISTENER } from '../../containers/Toast';
import EventEmitter from '../../utils/events';
import { onReviewPress } from '../../utils/review';
const SectionSeparator = React.memo(({ theme }) => (
<View
......@@ -255,6 +256,15 @@ class SettingsView extends React.Component {
theme={theme}
/>
<Separator theme={theme} />
<ListItem
title={I18n.t('Review_this_app')}
showActionIndicator
onPress={onReviewPress}
testID='settings-view-review-app'
right={this.renderDisclosure}
theme={theme}
/>
<Separator theme={theme} />
<ListItem
title={I18n.t('Share_this_app')}
showActionIndicator
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment