2025-12-07 21:27:23 +01:00
|
|
|
import type { AuthProviderInfo, RecordModel } from 'pocketbase';
|
|
|
|
|
import { usePocketbase } from './usePocketbase';
|
|
|
|
|
|
|
|
|
|
export interface LoggedInUser extends RecordModel {
|
|
|
|
|
id: string;
|
|
|
|
|
email: string;
|
|
|
|
|
emailVisibility: boolean;
|
|
|
|
|
verified: boolean;
|
|
|
|
|
name: string;
|
|
|
|
|
avatar?: string;
|
|
|
|
|
created: Date;
|
|
|
|
|
updated: Date;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const user = ref<LoggedInUser | null>(null);
|
|
|
|
|
const loading = ref<boolean>(false);
|
|
|
|
|
const error = ref<Error | null>(null);
|
2025-12-12 13:57:44 +01:00
|
|
|
let isInitialized = false;
|
2025-12-07 21:27:23 +01:00
|
|
|
|
|
|
|
|
export const useAuth = () => {
|
|
|
|
|
const pb = usePocketbase();
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
const userCollection = 'users';
|
|
|
|
|
|
|
|
|
|
const initAuth = async () => {
|
|
|
|
|
user.value = pb.authStore.record as LoggedInUser;
|
2026-01-28 16:18:20 +01:00
|
|
|
pb.authStore.onChange((_token, model) => (user.value = (model as LoggedInUser) ?? null));
|
2025-12-07 21:27:23 +01:00
|
|
|
};
|
|
|
|
|
|
2025-12-12 13:57:44 +01:00
|
|
|
if (!isInitialized) {
|
|
|
|
|
initAuth();
|
|
|
|
|
isInitialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-28 16:18:20 +01:00
|
|
|
const isAuthenticated = computed<boolean>(() => {
|
|
|
|
|
return !!user.value && pb.authStore.isValid;
|
|
|
|
|
});
|
2025-12-12 13:57:44 +01:00
|
|
|
|
2025-12-07 21:27:23 +01:00
|
|
|
const authProviders = async (): Promise<AuthProviderInfo[]> => {
|
|
|
|
|
const authMethods = await pb.collection(userCollection).listAuthMethods();
|
|
|
|
|
return authMethods.oauth2.enabled ? authMethods.oauth2.providers : [];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const login = async (provider: string) => {
|
|
|
|
|
loading.value = true;
|
|
|
|
|
error.value = null;
|
|
|
|
|
try {
|
|
|
|
|
const providers = await authProviders();
|
|
|
|
|
const providerData = providers.find((p) => p.name === provider);
|
|
|
|
|
if (!providerData) {
|
|
|
|
|
throw new Error(`${provider} OAuth is not configured`);
|
|
|
|
|
}
|
|
|
|
|
const response = await pb.collection(userCollection).authWithOAuth2({ provider });
|
|
|
|
|
user.value = response.record as LoggedInUser;
|
|
|
|
|
} catch (pbError) {
|
2026-01-28 16:18:20 +01:00
|
|
|
const err = pbError as Error;
|
|
|
|
|
console.error('[useAuth] Login failed:', err);
|
|
|
|
|
|
|
|
|
|
const message = err?.message?.toLowerCase() || '';
|
|
|
|
|
if (message.includes('not configured')) {
|
|
|
|
|
error.value = new Error('This login provider is not available. Contact admin.');
|
|
|
|
|
} else if (message.includes('denied') || message.includes('cancel')) {
|
|
|
|
|
error.value = new Error('Login was cancelled. Please try again.');
|
|
|
|
|
} else if (message.includes('network') || message.includes('fetch')) {
|
|
|
|
|
error.value = new Error('Connection failed. Check your internet and try again.');
|
|
|
|
|
} else {
|
|
|
|
|
error.value = new Error('Login failed. Please try again later.');
|
|
|
|
|
}
|
2025-12-07 21:27:23 +01:00
|
|
|
} finally {
|
|
|
|
|
loading.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const refreshAuth = async () => await pb.collection(userCollection).authRefresh();
|
|
|
|
|
|
|
|
|
|
const handleOAuthCallback = async () => {
|
|
|
|
|
user.value = pb.authStore.record as LoggedInUser;
|
|
|
|
|
if (isAuthenticated.value) {
|
|
|
|
|
await router.push('/dashboard');
|
|
|
|
|
} else {
|
|
|
|
|
await router.push('/');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const logout = () => {
|
|
|
|
|
user.value = null;
|
|
|
|
|
error.value = null;
|
2025-12-12 13:57:44 +01:00
|
|
|
pb.authStore.clear();
|
2025-12-07 21:27:23 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
user,
|
|
|
|
|
loading,
|
|
|
|
|
error,
|
|
|
|
|
isAuthenticated,
|
2026-01-28 16:18:20 +01:00
|
|
|
initAuth,
|
2025-12-07 21:27:23 +01:00
|
|
|
login,
|
|
|
|
|
logout,
|
|
|
|
|
refreshAuth,
|
|
|
|
|
handleOAuthCallback,
|
|
|
|
|
authProviders,
|
|
|
|
|
};
|
|
|
|
|
};
|