first commit
This commit is contained in:
384
bobu/app/stores/user.ts
Normal file
384
bobu/app/stores/user.ts
Normal file
@@ -0,0 +1,384 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import type { getAuth, User } from 'firebase/auth';
|
||||
import {
|
||||
serverTimestamp,
|
||||
doc,
|
||||
getDoc,
|
||||
setDoc,
|
||||
onSnapshot,
|
||||
} from 'firebase/firestore';
|
||||
import { createSession, logoutSession } from '@/utils/api/authFromFunction';
|
||||
import {
|
||||
createUserWithEmailAndPassword,
|
||||
updateProfile,
|
||||
signInWithEmailAndPassword,
|
||||
signOut as firebaseSignOut,
|
||||
} from 'firebase/auth';
|
||||
|
||||
let auth: ReturnType<typeof getAuth> | null = null;
|
||||
let usersCollection: any = null;
|
||||
let firebaseBase: string = '';
|
||||
|
||||
type UnsubscribeFn = (() => void) | null;
|
||||
|
||||
interface State {
|
||||
userLoggedIn: boolean;
|
||||
email: string;
|
||||
userRole: number;
|
||||
docId: string;
|
||||
isActive: boolean;
|
||||
name: string;
|
||||
profile_img: string;
|
||||
unsubscribe: UnsubscribeFn;
|
||||
}
|
||||
|
||||
interface RegisterValues {
|
||||
email: string;
|
||||
password: string;
|
||||
name: string;
|
||||
membership: string;
|
||||
isActive: boolean;
|
||||
profile_img: string;
|
||||
created: any;
|
||||
uid: string;
|
||||
phone: number;
|
||||
}
|
||||
|
||||
interface AuthenticateValues {
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
//delaying
|
||||
function sleep(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export const useUserStore = defineStore('user', {
|
||||
state: (): State => ({
|
||||
userLoggedIn: false,
|
||||
email: '',
|
||||
docId: '',
|
||||
userRole: 0,
|
||||
isActive: false,
|
||||
profile_img: '',
|
||||
name: '',
|
||||
unsubscribe: null,
|
||||
}),
|
||||
actions: {
|
||||
init() {
|
||||
const { $firebase } = useNuxtApp();
|
||||
const auth = $firebase.auth;
|
||||
let everLoggedIn = false;
|
||||
auth.onIdTokenChanged(async (user: User | null) => {
|
||||
if (user) {
|
||||
everLoggedIn = true;
|
||||
const idToken = await user.getIdToken();
|
||||
await createSession(idToken);
|
||||
this.userLoggedIn = true;
|
||||
this.initializeListener();
|
||||
} else if (everLoggedIn) {
|
||||
// only really sign out if we *were* logged in
|
||||
await logoutSession();
|
||||
this._resetStore();
|
||||
}
|
||||
});
|
||||
},
|
||||
_resetStore() {
|
||||
this.userLoggedIn = false;
|
||||
this.email = '';
|
||||
this.docId = '';
|
||||
this.userRole = 0;
|
||||
this.isActive = false;
|
||||
this.name = '';
|
||||
this.profile_img = '';
|
||||
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
this.unsubscribe = null;
|
||||
}
|
||||
},
|
||||
|
||||
initializeListener() {
|
||||
const { $firebase } = useNuxtApp();
|
||||
auth = $firebase.auth;
|
||||
usersCollection = $firebase.usersCollection;
|
||||
|
||||
if (!auth || !usersCollection) {
|
||||
throw new Error('Firebase not initialized');
|
||||
}
|
||||
|
||||
const user = auth.currentUser;
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
}
|
||||
if (user) {
|
||||
const userDocRef = doc(usersCollection, user.uid);
|
||||
this.unsubscribe = onSnapshot(userDocRef, (docSnapshot) => {
|
||||
const userData = docSnapshot.data();
|
||||
if (userData) {
|
||||
this.$patch({
|
||||
userRole: userData.role,
|
||||
isActive: userData.isActive,
|
||||
name: userData.name,
|
||||
profile_img: userData.thumbnail_url,
|
||||
docId: userData.docId,
|
||||
email: userData.email,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
async fetchUserInfo() {
|
||||
if (!auth || !usersCollection)
|
||||
throw new Error('Firebase not initialized');
|
||||
|
||||
const currentUser = auth.currentUser;
|
||||
if (!currentUser) return null;
|
||||
|
||||
const userDocRef = doc(usersCollection, currentUser.uid);
|
||||
const userSnap = await getDoc(userDocRef);
|
||||
|
||||
if (userSnap.exists()) {
|
||||
this.docId = userSnap.id;
|
||||
return this.docId;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
async register(values: RegisterValues) {
|
||||
if (!auth || !usersCollection)
|
||||
throw new Error('Firebase not initialized');
|
||||
|
||||
const userCred = await createUserWithEmailAndPassword(
|
||||
auth,
|
||||
values.email,
|
||||
values.password
|
||||
);
|
||||
|
||||
if (!userCred.user) {
|
||||
throw new Error('User creation failed.');
|
||||
}
|
||||
|
||||
const userId = userCred.user.uid;
|
||||
|
||||
// Use setDoc + doc() with serverTimestamp
|
||||
await setDoc(doc(usersCollection, userId), {
|
||||
docId: userId,
|
||||
name: values.name,
|
||||
email: values.email,
|
||||
membership: values.membership,
|
||||
role: 1,
|
||||
isActive: true,
|
||||
profile_img: '',
|
||||
created: serverTimestamp(),
|
||||
});
|
||||
|
||||
await updateProfile(userCred.user, {
|
||||
displayName: values.name,
|
||||
});
|
||||
|
||||
this.$patch({ userLoggedIn: true });
|
||||
},
|
||||
// register for admin
|
||||
|
||||
async registerFromAdmin(values: RegisterValues) {
|
||||
if (!auth || !usersCollection)
|
||||
throw new Error('Firebase not initialized');
|
||||
|
||||
try {
|
||||
// 1. Get the ID token of the currently logged-in admin user
|
||||
const idToken = await auth.currentUser?.getIdToken();
|
||||
|
||||
if (!idToken) {
|
||||
throw new Error(
|
||||
'Authentication token not found. Ensure the user is logged in.'
|
||||
);
|
||||
}
|
||||
|
||||
// 2. Send a request to the Cloud Function
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${idToken}`,
|
||||
},
|
||||
body: JSON.stringify(values),
|
||||
};
|
||||
const REGISTER_NEW_USER_URL = `${firebaseBase}/registerNewUser`;
|
||||
|
||||
const response = await fetch(REGISTER_NEW_USER_URL, requestOptions);
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || 'Registration failed.');
|
||||
}
|
||||
|
||||
// Use a notification or other UI method to inform the admin
|
||||
// toast.success(`New user registered with UID: ${data.uid}`);
|
||||
console.log('New user registered with UID:', data.uid);
|
||||
} catch (error) {
|
||||
// Use a notification or other UI method to display the error
|
||||
// toast.error(error.message);
|
||||
console.error('Error registering user:', error);
|
||||
}
|
||||
},
|
||||
|
||||
async registerBatchFromAdmin(users: Array<RegisterValues>) {
|
||||
if (!auth || !usersCollection)
|
||||
throw new Error('Firebase not initialized');
|
||||
|
||||
const results = [];
|
||||
|
||||
// 1. Get the ID token of the currently logged-in admin user
|
||||
const idToken = await auth.currentUser?.getIdToken();
|
||||
|
||||
if (!idToken) {
|
||||
throw new Error(
|
||||
'Authentication token not found. Ensure the user is logged in.'
|
||||
);
|
||||
}
|
||||
|
||||
// Iterate over each user and attempt to register
|
||||
for (let values of users) {
|
||||
console.log('values', values);
|
||||
|
||||
try {
|
||||
// 2. Send a request to the Cloud Function for each user
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${idToken}`,
|
||||
},
|
||||
body: JSON.stringify(values),
|
||||
};
|
||||
const REGISTER_NEW_USER_URL = `${firebaseBase}/registerNewUser`;
|
||||
|
||||
const response = await fetch(REGISTER_NEW_USER_URL, requestOptions);
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || 'Registration failed.');
|
||||
}
|
||||
|
||||
// Log or notify success for this user
|
||||
console.log('New user registered with UID:', data.uid);
|
||||
results.push({ success: true, email: values.email, uid: data.uid });
|
||||
} catch (error) {
|
||||
const errorMessage = (error as Error).message;
|
||||
console.error('Error registering user:', errorMessage);
|
||||
results.push({
|
||||
success: false,
|
||||
email: values.email,
|
||||
message: errorMessage,
|
||||
});
|
||||
}
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
// The results array will have the success status for each user
|
||||
return results;
|
||||
},
|
||||
|
||||
async visitorRegister(values: RegisterValues) {
|
||||
if (!auth || !usersCollection)
|
||||
throw new Error('Firebase not initialized');
|
||||
|
||||
try {
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(values),
|
||||
};
|
||||
const VISITOR_REGISTER_URL = `${firebaseBase}/visitorRegister`;
|
||||
const response = await fetch(VISITOR_REGISTER_URL, requestOptions);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || 'Registration failed.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error registering user:', error);
|
||||
}
|
||||
},
|
||||
async adminChangePassword(email: string, newPassword: string) {
|
||||
if (!auth || !usersCollection)
|
||||
throw new Error('Firebase not initialized');
|
||||
|
||||
try {
|
||||
// 1. Get the ID token of the currently logged-in admin user
|
||||
const idToken = await auth.currentUser?.getIdToken();
|
||||
|
||||
if (!idToken) {
|
||||
throw new Error(
|
||||
'Authentication token not found. Ensure the user is logged in.'
|
||||
);
|
||||
}
|
||||
|
||||
// Data to send
|
||||
const payload = {
|
||||
email: email,
|
||||
newPassword: newPassword,
|
||||
};
|
||||
|
||||
// 2. Send a request to the Cloud Function
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${idToken}`,
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
};
|
||||
const CHANGE_PASSWORD_URL = `${firebaseBase}/adminChangePassword`;
|
||||
const response = await fetch(CHANGE_PASSWORD_URL, requestOptions);
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || 'Password change failed.');
|
||||
}
|
||||
|
||||
// Use a notification or other UI method to inform the admin
|
||||
// toast.success(`Password changed successfully for email: ${email}`);
|
||||
console.log(`Password changed successfully for email:`, email);
|
||||
} catch (error) {
|
||||
// Use a notification or other UI method to display the error
|
||||
// toast.error(error.message);
|
||||
console.error('Error changing password:', error);
|
||||
}
|
||||
},
|
||||
//Logs in a user using Firebase Authentication and initializes the listener to monitor user data changes.
|
||||
async authenticate(values: AuthenticateValues) {
|
||||
const { $firebase } = useNuxtApp();
|
||||
auth = $firebase.auth;
|
||||
usersCollection = $firebase.usersCollection;
|
||||
|
||||
if (!auth || !usersCollection)
|
||||
throw new Error('Firebase not initialized');
|
||||
await signInWithEmailAndPassword(auth, values.email, values.password);
|
||||
},
|
||||
|
||||
async signOut() {
|
||||
const { $firebase } = useNuxtApp();
|
||||
const auth = $firebase.auth;
|
||||
if (!auth) throw new Error('Firebase not initialized');
|
||||
if (this.unsubscribe) {
|
||||
this.unsubscribe();
|
||||
this.unsubscribe = null;
|
||||
}
|
||||
await firebaseSignOut(auth);
|
||||
await logoutSession();
|
||||
this._resetStore();
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
isLoggedIn: (state: State) => state.userLoggedIn,
|
||||
currentRole: (state: State) => state.userRole,
|
||||
},
|
||||
});
|
||||
|
||||
export default useUserStore;
|
||||
Reference in New Issue
Block a user