apphouse
Version:
Component library for React that uses observable state management and theme-able components.
338 lines (300 loc) • 8.53 kB
text/typescript
import {
getAuth,
createUserWithEmailAndPassword,
signOut,
onAuthStateChanged,
signInWithEmailAndPassword,
updateProfile,
sendPasswordResetEmail
} from 'firebase/auth';
import { getDatabase, ref, onValue } from 'firebase/database';
import { makeAutoObservable } from 'mobx';
import { currentLocale } from '../app/i18n/Locale';
import {
UserProfile,
GET_FIREBASE_STORAGE_IMAGE_PROFILE_PATH,
GET_FIREBASE_STORAGE_RESIZED_IMAGE_PROFILE_PATH
} from './UserProfile';
import {
getStorage,
ref as storageRef,
getDownloadURL,
deleteObject
} from 'firebase/storage';
export interface UserType {
displayName: string;
language: string;
email?: string;
photoURL?: string;
uid?: string;
}
export class User {
authenticated: boolean;
authorized: boolean;
displayName: string;
language: string;
email?: string;
errorCode?: string;
errorMessage?: string;
firebaseUser: any;
photoURL?: string;
uid?: string;
firebase: any;
allowDiscovery: boolean;
analytics: any;
connected: boolean;
lastUpdated?: number;
profile: UserProfile;
profilePhotoToken?: string;
onLogout: () => void;
constructor(onLogout: () => void) {
this.authenticated = false; // NOTE: You can be authenticated but not authorized
this.authorized = false;
this.language = currentLocale.locale;
this.allowDiscovery = false;
this.displayName = '';
this.connected = false;
this.lastUpdated = undefined;
this.email = undefined;
this.profile = new UserProfile({});
this.onLogout = onLogout;
this.profilePhotoToken = undefined;
makeAutoObservable(this);
}
get hasAccess(): boolean {
return this.authenticated && this.authorized;
}
get isPremiumMember(): boolean {
return this.profile.membership === 'premium';
}
initFirebase = () => {
// Attach observer
const auth = getAuth();
onAuthStateChanged(auth, async (user) => {
if (user) {
// User is signed in, see docs for a list of available properties
// https://firebase.google.com/docs/reference/js/firebase.User
const uid = auth.currentUser?.uid;
this.setAuthorized(true);
this.setFirebaseUser(user);
this.setDisplayName(user?.displayName || undefined);
this.setPhotoURL(user?.photoURL || undefined);
this.setUid(uid);
this.setEmail(user?.email || undefined);
this.setAuthenticated(true);
this.detectConnectionState();
} else {
// User is signed out
this.setAuthorized(false);
this.setAuthenticated(true);
}
});
};
setFirebase = (firebase: any) => {
this.firebase = firebase;
};
setFirebaseUser = (user: any) => {
this.firebaseUser = user;
};
private setAuthorized = (value: boolean) => {
this.authorized = value;
};
setLanguage = (value: string) => {
this.language = value;
currentLocale.setStringsForLocale(value);
};
setEmail = (value?: string) => {
this.email = value;
};
setDisplayName = (value?: string) => {
this.displayName = value || '';
};
setUid = (value?: string) => {
this.uid = value;
};
setErrorCode = (value?: string) => {
this.errorCode = value;
};
setErrorMessage = (value?: string) => {
this.errorMessage = value;
};
private setAuthenticated = (value: boolean) => {
this.authenticated = value;
};
setPhotoURL = (value?: string) => {
this.photoURL = value;
};
static getProfileImageUrl = async (userId: string) => {
const storage = getStorage();
const imageRefUrl = GET_FIREBASE_STORAGE_RESIZED_IMAGE_PROFILE_PATH(userId);
const sRef = storageRef(storage, imageRefUrl);
return await getDownloadURL(sRef);
};
setAllowDiscovery = (value?: boolean) => {
this.allowDiscovery = value || false;
};
sendPasswordResetEmail = (email: string) => {
const auth = getAuth();
return sendPasswordResetEmail(auth, email);
};
signupWithEmailAndPassword = async (email: string, password: string) => {
this.setAuthenticated(false);
// using firebase v8
const auth = getAuth();
await createUserWithEmailAndPassword(auth, email.toLowerCase(), password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
this.setUid(user.uid);
this.setEmail(user?.email || undefined);
this.setAuthenticated(true);
this.setAuthorized(true);
// CREATE USER PROFILE WHEN SIGNING UP
})
.catch((error) => {
const errorCode = error.code;
const errorMessage = error.message;
this.setAuthenticated(true);
this.setAuthorized(false);
this.setErrorMessage(errorMessage);
this.setErrorCode(errorCode);
});
};
signIn = async (email: string, password: string): Promise<boolean> => {
console.log('signIn', email, password);
this.setAuthenticated(false);
const {
setUid,
setEmail,
setAuthenticated,
setAuthorized,
setErrorMessage,
setErrorCode
} = this;
// using firebase v8
const auth = getAuth();
const signedIn = await signInWithEmailAndPassword(
auth,
email.toLocaleLowerCase(),
password
)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
setUid(user.uid);
setEmail(user?.email || undefined);
setAuthenticated(true);
setAuthorized(true);
setErrorMessage(undefined);
setErrorCode(undefined);
return true;
})
.catch((error) => {
console.log('error', error);
const errorCode = error.code;
const errorMessage = error.message;
setAuthenticated(true);
setAuthorized(false);
setErrorMessage(errorMessage);
setErrorCode(errorCode);
return false;
});
return signedIn;
};
updateDisplayName = (displayName: string) => {
if (this.firebaseUser) {
// Updates the user attributes:
updateProfile(this.firebaseUser, {
displayName
}).then(
() => {
// Profile updated successfully!
const displayName = this.firebaseUser.displayName;
this.setDisplayName(displayName);
},
(error: any) => {
// An error happened.
console.log({ error });
}
);
}
};
updatePhotoUrl = (photoURL: string) => {
if (this.firebaseUser) {
// Updates the user attributes:
this.firebaseUser
.updateProfile({
photoURL
})
.then(
() => {
// Profile updated successfully!
const photoURL = this.firebaseUser.photoURL;
this.setPhotoURL(photoURL);
},
(error: any) => {
// An error happened.
console.log({ error });
}
);
}
};
logout = () => {
this.onLogout();
const auth = getAuth();
signOut(auth)
.then(() => {
// Sign-out successful.
this.setUid(undefined);
this.setAuthorized(false);
this.setAuthenticated(true);
this.setEmail(undefined);
this.setDisplayName(undefined);
this.setPhotoURL(undefined);
})
.catch((error) => {
console.log({ error });
// An error happened.
});
};
detectConnectionState() {
const db = getDatabase();
const connectedRef = ref(db, '.info/connected');
onValue(connectedRef, (snap) => {
if (snap.val() === true) {
this.setConnected(true);
} else {
this.setConnected(false);
}
});
}
setConnected = (value: boolean) => {
this.connected = value;
};
setLastUpdated = (value: number) => {
this.lastUpdated = value;
};
onDeleteImageProfile = async () => {
const email = this.email;
if (email) {
const storage = getStorage();
// Create a reference to the file to delete
const desertRef = storageRef(
storage,
GET_FIREBASE_STORAGE_IMAGE_PROFILE_PATH(email)
);
// Delete the file
await deleteObject(desertRef);
}
};
}
// export const GET_FIREBASE_STORAGE_IMAGE_PROFILE_PATH_URI = (
// email: string,
// token: string
// ) => {
// return `https://firebasestorage.googleapis.com/v0/b/${
// firebaseConfig.storageBucket
// }/o/${encodeURIComponent(
// GET_FIREBASE_STORAGE_IMAGE_PROFILE_PATH(email)
// )}?alt=media&token=${token}`;
// };