ethanneff/example

View on GitHub
src/features/RateApp/index.tsx

Summary

Maintainability
B
5 hrs
Test Coverage
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { StyleSheet } from 'react-native';
import Rate, { AndroidMarket } from 'react-native-rate';
import { Button, Input, Modal, Text, View } from '../../components';
import { spacing } from '../Config';
import { Rating } from './Rating';

type ModalState = 'default' | 'feedback' | 'review' | 'thank you';
type State = {
  feedback: string;
  modal: ModalState;
  rating: number;
};
const initialState: State = {
  feedback: '',
  modal: 'default',
  rating: 0,
};
const ratingMin = 4;
const ratingOptions = {
  // TODO: use configs
  AmazonPackageName: 'com.google.android.apps.maps',

  AppleAppID: '899247664',
  GooglePackageName: 'com.google.android.apps.maps',
  OtherAndroidURL: 'http://www.mywebsite.com/app/47172391',
  fallbackPlatformURL: 'http://www.mywebsite.com/myapp',
  openAppStoreIfInAppFails: true,
  preferInApp: true,
  preferredAndroidMarket: AndroidMarket.Google,
};

type CompleteState = {
  feedback: string;
  navigatedToAppStore: boolean;
  rating: number;
};

type Properties = {
  readonly onComplete: (completeState: CompleteState) => void;
};

export const RateApp = ({ onComplete }: Properties) => {
  const ratingReference = useRef(0);
  const navigatedToAppStore = useRef(false);
  const [form, setForm] = useState<State>(initialState);
  const styles = StyleSheet.create({
    title: { paddingBottom: spacing(4) },
  });
  const completeState = useMemo(
    () => ({
      feedback: form.feedback,
      navigatedToAppStore: navigatedToAppStore.current,
      rating: form.rating,
    }),
    [form.feedback, form.rating],
  );

  const handleReset = useCallback(() => {
    ratingReference.current = 0;
    setForm(initialState);
  }, []);

  const handleReviewApp = useCallback(() => {
    handleReset();
    onComplete({ ...completeState, navigatedToAppStore: true });
    Rate.rate(ratingOptions, () => false);
  }, [completeState, onComplete, handleReset]);

  const handleRating = useCallback((rating: number) => {
    ratingReference.current = rating;
    setForm((previous) => ({ ...previous, rating }));
    setTimeout(() => {
      const success = ratingReference.current >= ratingMin;
      setForm((previous) => ({
        ...previous,
        modal: success ? 'review' : 'feedback',
      }));
    }, 200);
  }, []);

  const handleTextChange = useCallback((feedback: string) => {
    setForm((previous) => ({ ...previous, feedback }));
  }, []);

  const handleFeedbackSubmit = useCallback(() => {
    setForm((previous) => ({ ...previous, modal: 'thank you' }));
  }, []);

  const handleComplete = useCallback(() => {
    onComplete(completeState);
  }, [completeState, onComplete]);

  return (
    <Modal
      onBackgroundPress={handleComplete}
      showOverlay
    >
      {form.modal === 'review' ? (
        <>
          <Text
            center
            style={styles.title}
            title="Thank you for your feedback!"
            type="h4"
          />
          <Text
            center
            style={styles.title}
            title="Do you mind reviewing us on the app store?"
          />
          <View style={{ flexDirection: 'row', justifyContent: 'center' }}>
            <Button
              center
              color="secondary"
              onPress={handleComplete}
              title="No Thanks"
            />
            <Button
              center
              color="accent"
              onPress={handleReviewApp}
              title="Okay"
            />
          </View>
        </>
      ) : form.modal === 'feedback' ? (
        <>
          <Text
            center
            style={styles.title}
            title="Thank you for your rating!"
            type="h4"
          />
          <Text
            center
            style={styles.title}
            title="Could you provide us some additional feedback to help us improve?"
          />
          <Input
            onChangeText={handleTextChange}
            onSubmitEditing={handleFeedbackSubmit}
            placeholder="How can we improve?"
            value={form.feedback}
          />
          <View style={{ flexDirection: 'row', justifyContent: 'center' }}>
            <Button
              center
              color="secondary"
              onPress={handleComplete}
              title="No Thanks"
            />
            <Button
              center
              color="accent"
              onPress={handleFeedbackSubmit}
              title="Submit"
            />
          </View>
        </>
      ) : form.modal === 'thank you' ? (
        <>
          <Text
            center
            style={styles.title}
            title="Your feedback has been submitted!"
            type="h4"
          />
          <Text
            center
            style={styles.title}
            title="Our team will review your feedback in the next few days."
          />
          <Button
            center
            color="accent"
            onPress={handleComplete}
            title="Close"
          />
        </>
      ) : (
        <>
          <Text
            center
            style={styles.title}
            title="Hello!"
            type="h4"
          />
          <Text
            center
            style={styles.title}
            title="How are your enjoying the app so far? Please tap a star to rate the app."
          />
          <Rating
            count={5}
            onPress={handleRating}
            rating={form.rating}
            size={spacing(8)}
          />
        </>
      )}
    </Modal>
  );
};