386 lines
11 KiB
TypeScript
386 lines
11 KiB
TypeScript
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);
|
|
await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for 100 milliseconds
|
|
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;
|