@@ -1,46 +1,46 @@
|
||||
import FingerprintJS from "@fingerprintjs/fingerprintjs";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { notification } from "antd";
|
||||
import {notification} from "antd";
|
||||
import axios from "axios";
|
||||
import { setUserId, setUserProperties } from "firebase/analytics";
|
||||
import {setUserId, setUserProperties} from "firebase/analytics";
|
||||
import {
|
||||
checkActionCode,
|
||||
confirmPasswordReset,
|
||||
sendPasswordResetEmail,
|
||||
signInWithEmailAndPassword,
|
||||
signOut,
|
||||
checkActionCode,
|
||||
confirmPasswordReset,
|
||||
sendPasswordResetEmail,
|
||||
signInWithEmailAndPassword,
|
||||
signOut,
|
||||
} from "firebase/auth";
|
||||
import { doc, getDoc, setDoc } from "firebase/firestore";
|
||||
import { getToken } from "firebase/messaging";
|
||||
import {doc, getDoc, setDoc} from "firebase/firestore";
|
||||
import {getToken} from "firebase/messaging";
|
||||
import i18next from "i18next";
|
||||
import LogRocket from "logrocket";
|
||||
import { all, call, delay, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { factory } from "../../App/App.container";
|
||||
import {all, call, delay, put, select, takeLatest} from "redux-saga/effects";
|
||||
import {factory} from "../../App/App.container";
|
||||
import {
|
||||
analytics,
|
||||
auth,
|
||||
firestore,
|
||||
getCurrentUser,
|
||||
logImEXEvent,
|
||||
messaging,
|
||||
updateCurrentUser,
|
||||
analytics,
|
||||
auth,
|
||||
firestore,
|
||||
getCurrentUser,
|
||||
logImEXEvent,
|
||||
messaging,
|
||||
updateCurrentUser,
|
||||
} from "../../firebase/firebase.utils";
|
||||
import {
|
||||
checkInstanceId,
|
||||
sendPasswordResetFailure,
|
||||
sendPasswordResetSuccess,
|
||||
setAuthlevel,
|
||||
setInstanceConflict,
|
||||
setInstanceId,
|
||||
setLocalFingerprint,
|
||||
signInFailure,
|
||||
signInSuccess,
|
||||
signOutFailure,
|
||||
signOutSuccess,
|
||||
unauthorizedUser,
|
||||
updateUserDetailsSuccess,
|
||||
validatePasswordResetFailure,
|
||||
validatePasswordResetSuccess,
|
||||
checkInstanceId,
|
||||
sendPasswordResetFailure,
|
||||
sendPasswordResetSuccess,
|
||||
setAuthlevel,
|
||||
setInstanceConflict,
|
||||
setInstanceId,
|
||||
setLocalFingerprint,
|
||||
signInFailure,
|
||||
signInSuccess,
|
||||
signOutFailure,
|
||||
signOutSuccess,
|
||||
unauthorizedUser,
|
||||
updateUserDetailsSuccess,
|
||||
validatePasswordResetFailure,
|
||||
validatePasswordResetSuccess,
|
||||
} from "./user.actions";
|
||||
import UserActionTypes from "./user.types";
|
||||
import client from "../../utils/GraphQLClient";
|
||||
@@ -50,289 +50,299 @@ import day from "../../utils/day";
|
||||
const fpPromise = FingerprintJS.load();
|
||||
|
||||
export function* onEmailSignInStart() {
|
||||
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
|
||||
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
|
||||
}
|
||||
export function* signInWithEmail({ payload: { email, password } }) {
|
||||
try {
|
||||
logImEXEvent("redux_sign_in_attempt", { user: email });
|
||||
|
||||
const { user } = yield signInWithEmailAndPassword(auth, email, password);
|
||||
export function* signInWithEmail({payload: {email, password}}) {
|
||||
try {
|
||||
logImEXEvent("redux_sign_in_attempt", {user: email});
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
logImEXEvent("redux_sign_in_failure", { user: email, error });
|
||||
}
|
||||
const {user} = yield signInWithEmailAndPassword(auth, email, password);
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
logImEXEvent("redux_sign_in_failure", {user: email, error});
|
||||
}
|
||||
}
|
||||
|
||||
export function* onCheckUserSession() {
|
||||
yield takeLatest(UserActionTypes.CHECK_USER_SESSION, isUserAuthenticated);
|
||||
yield takeLatest(UserActionTypes.CHECK_USER_SESSION, isUserAuthenticated);
|
||||
}
|
||||
|
||||
|
||||
export function* isUserAuthenticated() {
|
||||
try {
|
||||
logImEXEvent("redux_auth_check");
|
||||
|
||||
const user = yield getCurrentUser();
|
||||
if (!user) {
|
||||
yield put(unauthorizedUser());
|
||||
return;
|
||||
}
|
||||
|
||||
LogRocket.identify(user.email);
|
||||
|
||||
const eulaQuery = yield client.query({
|
||||
query: QUERY_EULA,
|
||||
variables: {
|
||||
now: day()
|
||||
},
|
||||
});
|
||||
|
||||
const eulaIsAccepted = eulaQuery.data.eulas.length > 0 && eulaQuery.data.eulas[0].eula_acceptances.length > 0;
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
eulaIsAccepted,
|
||||
currentEula: eulaIsAccepted ? null : eulaQuery.data.eulas[0],
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
}
|
||||
}
|
||||
export function* onSignOutStart() {
|
||||
yield takeLatest(UserActionTypes.SIGN_OUT_START, signOutStart);
|
||||
}
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
logImEXEvent("redux_sign_out");
|
||||
|
||||
const state = yield select();
|
||||
|
||||
//unsub from topic.
|
||||
|
||||
try {
|
||||
const fcm_tokens = yield getToken(messaging);
|
||||
yield call(axios.post, "/notifications/unsubscribe", {
|
||||
fcm_tokens,
|
||||
imexshopid: state.user.bodyshop.imexshopid,
|
||||
type: "messaging",
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("No FCM token. Skipping unsubscribe.");
|
||||
}
|
||||
logImEXEvent("redux_auth_check");
|
||||
|
||||
yield signOut(auth);
|
||||
yield put(signOutSuccess());
|
||||
localStorage.removeItem("token");
|
||||
} catch (error) {
|
||||
yield put(signOutFailure(error.message));
|
||||
}
|
||||
const user = yield getCurrentUser();
|
||||
if (!user) {
|
||||
yield put(unauthorizedUser());
|
||||
return;
|
||||
}
|
||||
|
||||
LogRocket.identify(user.email);
|
||||
|
||||
const eulaQuery = yield client.query({
|
||||
query: QUERY_EULA,
|
||||
variables: {
|
||||
now: day()
|
||||
},
|
||||
});
|
||||
|
||||
const eulaIsAccepted = eulaQuery.data.eulas.length > 0 && eulaQuery.data.eulas[0].eula_acceptances.length > 0;
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
eulaIsAccepted,
|
||||
currentEula: eulaIsAccepted ? null : eulaQuery.data.eulas[0],
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSignOutStart() {
|
||||
yield takeLatest(UserActionTypes.SIGN_OUT_START, signOutStart);
|
||||
}
|
||||
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
logImEXEvent("redux_sign_out");
|
||||
|
||||
const state = yield select();
|
||||
|
||||
//unsub from topic.
|
||||
|
||||
try {
|
||||
const fcm_tokens = yield getToken(messaging);
|
||||
yield call(axios.post, "/notifications/unsubscribe", {
|
||||
fcm_tokens,
|
||||
imexshopid: state.user.bodyshop.imexshopid,
|
||||
type: "messaging",
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("No FCM token. Skipping unsubscribe.");
|
||||
}
|
||||
|
||||
yield signOut(auth);
|
||||
yield put(signOutSuccess());
|
||||
localStorage.removeItem("token");
|
||||
} catch (error) {
|
||||
yield put(signOutFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onUpdateUserDetails() {
|
||||
yield takeLatest(UserActionTypes.UPDATE_USER_DETAILS, updateUserDetails);
|
||||
yield takeLatest(UserActionTypes.UPDATE_USER_DETAILS, updateUserDetails);
|
||||
}
|
||||
|
||||
export function* updateUserDetails(userDetails) {
|
||||
try {
|
||||
const updatedDetails = yield updateCurrentUser(userDetails.payload);
|
||||
try {
|
||||
const updatedDetails = yield updateCurrentUser(userDetails.payload);
|
||||
|
||||
yield put(updateUserDetailsSuccess(updatedDetails));
|
||||
notification.open({
|
||||
type: "success",
|
||||
message: i18next.t("profile.successes.updated"),
|
||||
});
|
||||
} catch (error) {
|
||||
//yield put(signOutFailure(error.message));
|
||||
}
|
||||
yield put(updateUserDetailsSuccess(updatedDetails));
|
||||
notification.open({
|
||||
type: "success",
|
||||
message: i18next.t("profile.successes.updated"),
|
||||
});
|
||||
} catch (error) {
|
||||
//yield put(signOutFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSetInstanceId() {
|
||||
yield takeLatest(UserActionTypes.SET_INSTANCE_ID, setInstanceIdSaga);
|
||||
yield takeLatest(UserActionTypes.SET_INSTANCE_ID, setInstanceIdSaga);
|
||||
}
|
||||
export function* setInstanceIdSaga({ payload: uid }) {
|
||||
try {
|
||||
const userInstanceRef = doc(firestore, `userInstance/${uid}`);
|
||||
|
||||
// Get the visitor identifier when you need it.
|
||||
const fp = yield fpPromise;
|
||||
const result = yield fp.get();
|
||||
yield setDoc(userInstanceRef, {
|
||||
timestamp: new Date(),
|
||||
fingerprint: result.visitorId,
|
||||
});
|
||||
export function* setInstanceIdSaga({payload: uid}) {
|
||||
try {
|
||||
const userInstanceRef = doc(firestore, `userInstance/${uid}`);
|
||||
|
||||
yield put(setLocalFingerprint(result.visitorId));
|
||||
yield delay(5 * 60 * 1000);
|
||||
if (process.env.NODE_ENV === "production") yield put(checkInstanceId(uid));
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
// Get the visitor identifier when you need it.
|
||||
const fp = yield fpPromise;
|
||||
const result = yield fp.get();
|
||||
yield setDoc(userInstanceRef, {
|
||||
timestamp: new Date(),
|
||||
fingerprint: result.visitorId,
|
||||
});
|
||||
|
||||
yield put(setLocalFingerprint(result.visitorId));
|
||||
yield delay(5 * 60 * 1000);
|
||||
if (process.env.NODE_ENV === "production") yield put(checkInstanceId(uid));
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onCheckInstanceId() {
|
||||
yield takeLatest(UserActionTypes.CHECK_INSTANCE_ID, checkInstanceIdSaga);
|
||||
yield takeLatest(UserActionTypes.CHECK_INSTANCE_ID, checkInstanceIdSaga);
|
||||
}
|
||||
export function* checkInstanceIdSaga({ payload: uid }) {
|
||||
try {
|
||||
const snapshot = yield getDoc(doc(firestore, `userInstance/${uid}`));
|
||||
let fingerprint = yield select((state) => state.user.fingerprint);
|
||||
yield put(setInstanceConflict());
|
||||
if (snapshot.data().fingerprint === fingerprint) {
|
||||
yield delay(5 * 60 * 1000);
|
||||
yield put(checkInstanceId(uid));
|
||||
} else {
|
||||
console.log("ERROR: Fingerprints do not match. Conflict detected.");
|
||||
logImEXEvent("instance_confict");
|
||||
yield put(setInstanceConflict());
|
||||
|
||||
export function* checkInstanceIdSaga({payload: uid}) {
|
||||
try {
|
||||
const snapshot = yield getDoc(doc(firestore, `userInstance/${uid}`));
|
||||
let fingerprint = yield select((state) => state.user.fingerprint);
|
||||
yield put(setInstanceConflict());
|
||||
if (snapshot.data().fingerprint === fingerprint) {
|
||||
yield delay(5 * 60 * 1000);
|
||||
yield put(checkInstanceId(uid));
|
||||
} else {
|
||||
console.log("ERROR: Fingerprints do not match. Conflict detected.");
|
||||
logImEXEvent("instance_confict");
|
||||
yield put(setInstanceConflict());
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSignInSuccess() {
|
||||
yield takeLatest(UserActionTypes.SIGN_IN_SUCCESS, signInSuccessSaga);
|
||||
yield takeLatest(UserActionTypes.SIGN_IN_SUCCESS, signInSuccessSaga);
|
||||
}
|
||||
|
||||
export function* signInSuccessSaga({ payload }) {
|
||||
LogRocket.identify(payload.email);
|
||||
export function* signInSuccessSaga({payload}) {
|
||||
LogRocket.identify(payload.email);
|
||||
|
||||
try {
|
||||
// window.$crisp.push([
|
||||
// "set",
|
||||
// "user:nickname",
|
||||
// [payload.displayName || payload.email],
|
||||
// ]);
|
||||
try {
|
||||
// window.$crisp.push([
|
||||
// "set",
|
||||
// "user:nickname",
|
||||
// [payload.displayName || payload.email],
|
||||
// ]);
|
||||
|
||||
// window.$crisp.push(["set", "session:segments", [["rome-user"]]]);
|
||||
// window.$crisp.push(["set", "session:segments", [["rome-user"]]]);
|
||||
|
||||
Sentry.setUser({
|
||||
email: payload.email,
|
||||
username: payload.displayName || payload.email,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error updating Crisp settings.", error);
|
||||
}
|
||||
Sentry.setUser({
|
||||
email: payload.email,
|
||||
username: payload.displayName || payload.email,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error updating Crisp settings.", error);
|
||||
}
|
||||
|
||||
setUserId(analytics, payload.email);
|
||||
setUserProperties(analytics, payload);
|
||||
yield logImEXEvent("redux_sign_in_success");
|
||||
setUserId(analytics, payload.email);
|
||||
setUserProperties(analytics, payload);
|
||||
yield logImEXEvent("redux_sign_in_success");
|
||||
}
|
||||
|
||||
export function* onSendPasswordResetStart() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
}
|
||||
export function* sendPasswordResetEmailSaga({ payload }) {
|
||||
try {
|
||||
yield sendPasswordResetEmail(auth, payload, {
|
||||
url: "https://romeonline.io/passwordreset",
|
||||
});
|
||||
|
||||
yield put(sendPasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(sendPasswordResetFailure(error.message));
|
||||
}
|
||||
export function* sendPasswordResetEmailSaga({payload}) {
|
||||
try {
|
||||
yield sendPasswordResetEmail(auth, payload, {
|
||||
url: "https://romeonline.io/passwordreset",
|
||||
});
|
||||
|
||||
yield put(sendPasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(sendPasswordResetFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onValidatePasswordResetStart() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.VALIDATE_PASSWORD_RESET_START,
|
||||
validatePasswordResetStart
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.VALIDATE_PASSWORD_RESET_START,
|
||||
validatePasswordResetStart
|
||||
);
|
||||
}
|
||||
export function* validatePasswordResetStart({ payload: { password, code } }) {
|
||||
try {
|
||||
checkActionCode(auth, code);
|
||||
yield confirmPasswordReset(auth, code, password);
|
||||
yield put(validatePasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(validatePasswordResetFailure(error.message));
|
||||
}
|
||||
|
||||
export function* validatePasswordResetStart({payload: {password, code}}) {
|
||||
try {
|
||||
checkActionCode(auth, code);
|
||||
yield confirmPasswordReset(auth, code, password);
|
||||
yield put(validatePasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(validatePasswordResetFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSetShopDetails() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.SET_SHOP_DETAILS,
|
||||
SetAuthLevelFromShopDetails
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SET_SHOP_DETAILS,
|
||||
SetAuthLevelFromShopDetails
|
||||
);
|
||||
}
|
||||
export function* SetAuthLevelFromShopDetails({ payload }) {
|
||||
try {
|
||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||
|
||||
export function* SetAuthLevelFromShopDetails({payload}) {
|
||||
try {
|
||||
//console.log("Setting shop timezone.");
|
||||
// dayjs.tz.setDefault(payload.timezone);
|
||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||
try {
|
||||
//console.log("Setting shop timezone.");
|
||||
// dayjs.tz.setDefault(payload.timezone);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
factory.client(payload.imexshopid);
|
||||
|
||||
const authRecord = payload.associations.filter(
|
||||
(a) => a.useremail.toLowerCase() === userEmail.toLowerCase()
|
||||
);
|
||||
|
||||
yield put(setAuthlevel(authRecord[0] ? authRecord[0].authlevel : 0));
|
||||
yield put(
|
||||
updateUserDetailsSuccess(
|
||||
authRecord[0]
|
||||
? {validemail: authRecord[0].user.validemail}
|
||||
: {validemail: false}
|
||||
)
|
||||
);
|
||||
|
||||
if (payload.features.singleDeviceOnly) {
|
||||
const user = yield select((state) => state.user.currentUser);
|
||||
|
||||
if (!(user.email.includes("@imex.") || user.email.includes("@rome.")))
|
||||
yield put(setInstanceId(user.uid));
|
||||
}
|
||||
|
||||
try {
|
||||
// window.$crisp.push(["set", "user:company", [payload.shopname]]);
|
||||
// if (authRecord[0] && authRecord[0].user.validemail) {
|
||||
// window.$crisp.push(["set", "user:email", [authRecord[0].user.email]]);
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error("Couldnt find $crisp.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
yield put(signInFailure(error.message));
|
||||
}
|
||||
|
||||
factory.client(payload.imexshopid);
|
||||
|
||||
const authRecord = payload.associations.filter(
|
||||
(a) => a.useremail.toLowerCase() === userEmail.toLowerCase()
|
||||
);
|
||||
|
||||
yield put(setAuthlevel(authRecord[0] ? authRecord[0].authlevel : 0));
|
||||
yield put(
|
||||
updateUserDetailsSuccess(
|
||||
authRecord[0]
|
||||
? { validemail: authRecord[0].user.validemail }
|
||||
: { validemail: false }
|
||||
)
|
||||
);
|
||||
|
||||
if (payload.features.singleDeviceOnly) {
|
||||
const user = yield select((state) => state.user.currentUser);
|
||||
|
||||
if (!(user.email.includes("@imex.") || user.email.includes("@rome.")))
|
||||
yield put(setInstanceId(user.uid));
|
||||
}
|
||||
|
||||
try {
|
||||
// window.$crisp.push(["set", "user:company", [payload.shopname]]);
|
||||
// if (authRecord[0] && authRecord[0].user.validemail) {
|
||||
// window.$crisp.push(["set", "user:email", [authRecord[0].user.email]]);
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error("Couldnt find $crisp.");
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* userSagas() {
|
||||
yield all([
|
||||
call(onEmailSignInStart),
|
||||
call(onCheckUserSession),
|
||||
call(onSignOutStart),
|
||||
call(onUpdateUserDetails),
|
||||
call(onSetInstanceId),
|
||||
call(onCheckInstanceId),
|
||||
call(onSignInSuccess),
|
||||
call(onSendPasswordResetStart),
|
||||
call(onValidatePasswordResetStart),
|
||||
call(onSetShopDetails),
|
||||
]);
|
||||
yield all([
|
||||
call(onEmailSignInStart),
|
||||
call(onCheckUserSession),
|
||||
call(onSignOutStart),
|
||||
call(onUpdateUserDetails),
|
||||
call(onSetInstanceId),
|
||||
call(onCheckInstanceId),
|
||||
call(onSignInSuccess),
|
||||
call(onSendPasswordResetStart),
|
||||
call(onValidatePasswordResetStart),
|
||||
call(onSetShopDetails),
|
||||
]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user