Files
bobu/bobu/app/stores/user.ts
2025-07-15 11:23:20 +09:00

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;