10 |
Privacy Policy
11 |
12 | Mohammad Shbool built the Learn Quran app as an Open Source app. This
13 | SERVICE is provided by Mohammad Shbool at no cost and is intended for use
14 | as is.
15 |
16 |
17 | This page is used to inform visitors regarding my policies with the
18 | collection, use, and disclosure of Personal Information if anyone decided
19 | to use my Service.
20 |
21 |
22 | If you choose to use my Service, then you agree to the collection and use
23 | of information in relation to this policy. The Personal Information that I
24 | collect is used for providing and improving the Service. I will not use or
25 | share your information with anyone except as described in this Privacy
26 | Policy.
27 |
28 |
29 | The terms used in this Privacy Policy have the same meanings as in our
30 | Terms and Conditions, which is accessible at Learn Quran unless otherwise
31 | defined in this Privacy Policy.
32 |
33 |
34 | Information Collection and Use
35 |
36 |
37 | For a better experience, while using our Service, I may require you to
38 | provide us with certain personally identifiable information, including but
39 | not limited to email, username. The information that I request will be
40 | retained on your device and is not collected by me in any way.
41 |
42 |
43 | The app does use third party services that may collect information used to
44 | identify you.
45 |
46 |
47 |
48 | Link to privacy policy of third party service providers used by the app
49 |
50 |
51 |
52 | Log Data
53 |
54 |
55 | I want to inform you that whenever you use my Service, in a case of an
56 | error in the app I collect data and information (through third party
57 | products) on your phone called Log Data. This Log Data may include
58 | information such as your device Internet Protocol (“IP”) address, device
59 | name, operating system version, the configuration of the app when
60 | utilizing my Service, the time and date of your use of the Service, and
61 | other statistics.
62 |
63 |
64 | Cookies
65 |
66 |
67 | Cookies are files with a small amount of data that are commonly used as
68 | anonymous unique identifiers. These are sent to your browser from the
69 | websites that you visit and are stored on your device's internal
70 | memory.
71 |
72 |
73 | This Service does not use these “cookies” explicitly. However, the app may
74 | use third party code and libraries that use “cookies” to collect
75 | information and improve their services. You have the option to either
76 | accept or refuse these cookies and know when a cookie is being sent to
77 | your device. If you choose to refuse our cookies, you may not be able to
78 | use some portions of this Service.
79 |
80 |
81 | Service Providers
82 |
83 |
84 | I may employ third-party companies and individuals due to the following
85 | reasons:
86 |
87 |
88 | - To facilitate our Service;
89 | - To provide the Service on our behalf;
90 | - To perform Service-related services; or
91 | - To assist us in analyzing how our Service is used.
92 |
93 |
94 | I want to inform users of this Service that these third parties have
95 | access to your Personal Information. The reason is to perform the tasks
96 | assigned to them on our behalf. However, they are obligated not to
97 | disclose or use the information for any other purpose.
98 |
99 |
100 | Security
101 |
102 |
103 | I value your trust in providing us your Personal Information, thus we are
104 | striving to use commercially acceptable means of protecting it. But
105 | remember that no method of transmission over the internet, or method of
106 | electronic storage is 100% secure and reliable, and I cannot guarantee its
107 | absolute security.
108 |
109 |
110 | Links to Other Sites
111 |
112 |
113 | This Service may contain links to other sites. If you click on a
114 | third-party link, you will be directed to that site. Note that these
115 | external sites are not operated by me. Therefore, I strongly advise you to
116 | review the Privacy Policy of these websites. I have no control over and
117 | assume no responsibility for the content, privacy policies, or practices
118 | of any third-party sites or services.
119 |
120 |
121 | Children’s Privacy
122 |
123 |
124 | These Services do not address anyone under the age of 13. I do not
125 | knowingly collect personally identifiable information from children under
126 | 13. In the case I discover that a child under 13 has provided me with
127 | personal information, I immediately delete this from our servers. If you
128 | are a parent or guardian and you are aware that your child has provided us
129 | with personal information, please contact me so that I will be able to do
130 | necessary actions.
131 |
132 |
133 | Changes to This Privacy Policy
134 |
135 |
136 | I may update our Privacy Policy from time to time. Thus, you are advised
137 | to review this page periodically for any changes. I will notify you of any
138 | changes by posting the new Privacy Policy on this page. These changes are
139 | effective immediately after they are posted on this page.
140 |
141 |
142 | Contact Us
143 |
144 |
145 | If you have any questions or suggestions about my Privacy Policy, do not
146 | hesitate to contact me at
147 |
148 | contactus.learnquran@gmail.com
149 |
150 |
151 |
152 |
153 | This Privacy Policy was originally generated by
154 |
155 | www.spanprivacypolicytemplate.net
156 |
157 |
158 |
159 |
160 | );
161 | PrivacyPolicy.propTypes = {
162 | t: PropTypes.func,
163 | };
164 |
165 | export default withTranslation()(PrivacyPolicy);
166 |
--------------------------------------------------------------------------------
/src/Firebase.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/display-name */
2 | import React from 'react';
3 | import app from 'firebase/app';
4 | import moment from 'moment';
5 |
6 | // Firebase dependencies
7 | import 'firebase/auth';
8 | import 'firebase/database';
9 | import 'firebase/storage';
10 |
11 | const config = {
12 | apiKey: process.env.REACT_APP_API_KEY,
13 | authDomain: process.env.REACT_APP_AUTH_DOMAIN,
14 | databaseURL: process.env.REACT_APP_DATABASE_URL,
15 | projectId: process.env.REACT_APP_PROJECT_ID,
16 | storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
17 | messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
18 | appId: process.env.REACT_APP_APP_ID,
19 | };
20 |
21 | class Firebase {
22 | constructor() {
23 | app.initializeApp(config);
24 |
25 | this.auth = app.auth;
26 | this.database = app.database();
27 | this.storage = app.storage;
28 | this.isLoggedIn = false;
29 | }
30 |
31 | errors = [
32 | 'check-your-internet-connection',
33 | 'auth/email-already-in-use',
34 | 'auth/user-disabled',
35 | 'auth/user-not-found',
36 | 'auth/wrong-password',
37 | 'auth/email-already-in-use',
38 | 'auth/invalid-email',
39 | 'auth/weak-password',
40 | 'username-already-exists',
41 | 'an-error-occured-please-try-again-later',
42 | 'auth/requires-recent-login',
43 | 'auth/user-mismatch',
44 | 'auth/user-not-found',
45 | 'auth/invalid-credential',
46 | ];
47 |
48 | getErrorMessage = code =>
49 | this.errors.includes(code) ? code : 'check-your-internet-connection';
50 |
51 | signIn = ({ email, password }) =>
52 | new Promise((resovle, reject) => {
53 | this.auth()
54 | .signInWithEmailAndPassword(email, password)
55 | .then(() => resovle())
56 | .catch(({ code, message }) => {
57 | reject(this.getErrorMessage(code) || message);
58 | });
59 | });
60 | createUser = ({ email, password, username, language }) =>
61 | new Promise((resolve, reject) => {
62 | this.isUsernameDuplicated(username)
63 | .then(() => {
64 | this.auth()
65 | .createUserWithEmailAndPassword(email, password)
66 | .then(({ user }) => {
67 | if (user && user.uid) {
68 | let updates = {};
69 | updates['users/private/' + user.uid] = {
70 | uid: user.uid,
71 | email: email,
72 | language: language,
73 | username: username,
74 | points: 0,
75 | lastPlayed: 'never-played',
76 | createdAt: moment()
77 | .locale('en')
78 | .format(),
79 | };
80 | updates['users/public/' + user.uid] = {
81 | username: username,
82 | points: 0,
83 | lastPlayed: 'never-played',
84 | };
85 | this.database.ref().update(updates);
86 | resolve();
87 | }
88 | })
89 | .catch(({ code, message }) => {
90 | reject(this.getErrorMessage(code) || message);
91 | });
92 | })
93 | .catch(err => reject(err));
94 | });
95 | resetPassword = (email, lang) =>
96 | new Promise((resolve, reject) => {
97 | const auth = this.auth();
98 | auth.languageCode = lang;
99 | auth
100 | .sendPasswordResetEmail(email)
101 | .then(() => resolve())
102 | .catch(error => reject(error.message));
103 | });
104 | getUser = () =>
105 | new Promise((resolve, reject) => {
106 | this.database
107 | .ref(`users/private/${this.auth().currentUser.uid}`)
108 | .once('value')
109 | .then(snapshot => {
110 | resolve(snapshot.val());
111 | })
112 | .catch(error => reject(error.message));
113 | });
114 | isUsernameDuplicated = username =>
115 | new Promise((resolve, reject) => {
116 | this.database
117 | .ref('users/public')
118 | .orderByChild('username')
119 | .equalTo(username)
120 | .once('value')
121 | .then(snapshot => {
122 | if (snapshot.val()) {
123 | reject('username-already-exists');
124 | } else {
125 | resolve();
126 | }
127 | })
128 | .catch(({ code, message }) => {
129 | reject(this.getErrorMessage(code) || message);
130 | });
131 | });
132 | getLeaderboard = () =>
133 | new Promise((resolve, reject) => {
134 | this.database
135 | .ref('users/public')
136 | .orderByChild('points')
137 | .once('value')
138 | .then(snapshot => {
139 | resolve(snapshot.val());
140 | });
141 | });
142 | updateUserOnDB = (_updates, _public = false, _private = true) =>
143 | new Promise((resolve, reject) => {
144 | if (!_public && !_private) return;
145 | const { uid } = this.auth().currentUser;
146 | const promises = [];
147 | if (_public)
148 | promises.push(
149 | this.database.ref(`users/public/${uid}`).update(_updates),
150 | );
151 | if (_private)
152 | promises.push(
153 | this.database.ref(`users/private/${uid}`).update(_updates),
154 | );
155 | Promise.all(promises)
156 | .then(() => resolve())
157 | .catch(() => reject('an-error-occured-please-try-again-later'));
158 | });
159 | updateUserEmail = email =>
160 | new Promise((resolve, reject) => {
161 | this.auth()
162 | .currentUser.updateEmail(email)
163 | .then(() => this.updateUserOnDB({ email }).then(() => resolve()))
164 | .catch(({ code, message }) => {
165 | reject(this.getErrorMessage(code) || message);
166 | });
167 | });
168 | updateUserPassword = password =>
169 | new Promise((resolve, reject) => {
170 | this.auth()
171 | .currentUser.updatePassword(password)
172 | .then(() => resolve())
173 | .catch(({ code, message }) => {
174 | reject(this.getErrorMessage(code) || message);
175 | });
176 | });
177 | reauthenticate = password =>
178 | new Promise((resolve, reject) => {
179 | const user = this.auth().currentUser;
180 | const credintial = this.auth.EmailAuthProvider.credential(
181 | user.email,
182 | password,
183 | );
184 | user
185 | .reauthenticateWithCredential(credintial)
186 | .then(() => resolve())
187 | .catch(({ code, message }) => {
188 | reject(this.getErrorMessage(code) || message);
189 | });
190 | });
191 | getAsset = assetId =>
192 | new Promise((resolve, reject) => {
193 | this.storage()
194 | .ref(`audio/${assetId}.mp3`)
195 | .getDownloadURL()
196 | .then(url => resolve(url))
197 | .catch(({ code, message }) => {
198 | reject(this.getErrorMessage(code) || message);
199 | });
200 | });
201 | updateUserPoints = newPoints =>
202 | new Promise((resolve, reject) => {
203 | this.getUser()
204 | .then(({ points }) => {
205 | this.updateUserOnDB({ points: points + newPoints }, true)
206 | .then(() => resolve())
207 | .catch(() => reject());
208 | })
209 | .catch(() => reject());
210 | });
211 | updateUserLastPlayed = lastPlayed =>
212 | new Promise(() => {
213 | this.getUser()
214 | .then(({ points }) => {
215 | this.updateUserOnDB({ lastPlayed }, true)
216 | .then(() => {})
217 | .catch(() => {});
218 | })
219 | .catch(() => {});
220 | });
221 | }
222 |
223 | const FirebaseContext = React.createContext(null);
224 |
225 | const withFirebase = Component => props => (
226 |