UNPKG

@profullstack/auth-system

Version:

Flexible authentication system with user registration, login/logout, password reset, and session management

354 lines (295 loc) 11.2 kB
/** * Settings Page Example * * This example shows how to use the AuthClient to implement a settings page * that includes profile management, password changes, and account deletion. */ import { AuthClient } from './auth-client.js'; /** * Initialize settings page */ export async function initSettingsPage() { try { // Create AuthClient instance const authClient = await createAuthClient(); // Check authentication status const authStatus = await authClient.checkAuthStatus(); if (!authStatus.authenticated) { console.log('Not authenticated, redirecting to login page:', authStatus.message); window.router.navigate('/login'); return; } console.log('Authentication verified with server'); // Load user profile data await loadUserProfile(authClient); // Initialize profile form initProfileForm(authClient); // Initialize password form initPasswordForm(authClient); // Initialize delete account button initDeleteAccountButton(authClient); } catch (error) { console.error('Error initializing settings page:', error); window.router.navigate('/login'); } } /** * Load user profile data * @param {AuthClient} authClient - AuthClient instance */ async function loadUserProfile(authClient) { try { // Get user profile const profileResult = await authClient.getProfile(); const user = profileResult.user; // Populate profile form fields const emailField = document.getElementById('profile-email'); if (emailField) { emailField.value = user.email; emailField.disabled = true; // Email is typically not editable } // Populate other profile fields const firstNameField = document.getElementById('profile-first-name'); if (firstNameField) { firstNameField.value = user.profile.firstName || ''; } const lastNameField = document.getElementById('profile-last-name'); if (lastNameField) { lastNameField.value = user.profile.lastName || ''; } const phoneField = document.getElementById('profile-phone'); if (phoneField) { phoneField.value = user.profile.phoneNumber || ''; } // Display subscription information if available const subscriptionInfo = document.getElementById('subscription-info'); if (subscriptionInfo && user.subscription) { const plan = user.subscription.plan || 'Unknown'; const status = user.subscription.status || 'Unknown'; const expiresAt = user.subscription.expiresAt ? new Date(user.subscription.expiresAt).toLocaleDateString() : 'N/A'; subscriptionInfo.innerHTML = ` <div class="subscription-details"> <p><strong>Plan:</strong> ${plan}</p> <p><strong>Status:</strong> ${status}</p> <p><strong>Expires:</strong> ${expiresAt}</p> </div> `; } } catch (error) { console.error('Error loading user profile:', error); // Import PfDialog component const { default: PfDialog } = await import('./components/pf-dialog.js'); PfDialog.alert('Error loading profile data. Please try again later.'); } } /** * Initialize profile form * @param {AuthClient} authClient - AuthClient instance */ function initProfileForm(authClient) { const profileForm = document.getElementById('profile-form'); if (!profileForm) return; profileForm.addEventListener('submit', async (e) => { e.preventDefault(); // Show loading state const submitButton = profileForm.querySelector('button[type="submit"]'); const originalButtonText = submitButton.textContent; submitButton.textContent = 'Updating...'; submitButton.disabled = true; try { // Get profile data from form const firstName = document.getElementById('profile-first-name').value; const lastName = document.getElementById('profile-last-name').value; const phoneNumber = document.getElementById('profile-phone').value; // Update profile const result = await authClient.updateProfile({ firstName, lastName, phoneNumber }); console.log('Profile updated successfully:', result); // Reset button state submitButton.textContent = originalButtonText; submitButton.disabled = false; // Show success message const { default: PfDialog } = await import('./components/pf-dialog.js'); PfDialog.alert('Profile updated successfully!'); } catch (error) { console.error('Error updating profile:', error); // Reset button state submitButton.textContent = originalButtonText; submitButton.disabled = false; // Show error message const { default: PfDialog } = await import('./components/pf-dialog.js'); PfDialog.alert('Error updating profile: ' + (error.message || 'Unknown error')); } }); } /** * Initialize password form * @param {AuthClient} authClient - AuthClient instance */ function initPasswordForm(authClient) { const passwordForm = document.getElementById('password-form'); if (!passwordForm) return; passwordForm.addEventListener('submit', async (e) => { e.preventDefault(); // Show loading state const submitButton = passwordForm.querySelector('button[type="submit"]'); const originalButtonText = submitButton.textContent; submitButton.textContent = 'Updating...'; submitButton.disabled = true; try { // Get password data from form const currentPassword = document.getElementById('current-password').value; const newPassword = document.getElementById('new-password').value; const confirmPassword = document.getElementById('confirm-password').value; // Validate passwords if (newPassword !== confirmPassword) { const { default: PfDialog } = await import('./components/pf-dialog.js'); PfDialog.alert('New passwords do not match'); // Reset button state submitButton.textContent = originalButtonText; submitButton.disabled = false; return; } // Change password const result = await authClient.changePassword({ currentPassword, newPassword }); console.log('Password changed successfully:', result); // Reset form passwordForm.reset(); // Reset button state submitButton.textContent = originalButtonText; submitButton.disabled = false; // Show success message const { default: PfDialog } = await import('./components/pf-dialog.js'); PfDialog.alert('Password changed successfully!'); } catch (error) { console.error('Error changing password:', error); // Reset button state submitButton.textContent = originalButtonText; submitButton.disabled = false; // Show error message const { default: PfDialog } = await import('./components/pf-dialog.js'); PfDialog.alert('Error changing password: ' + (error.message || 'Unknown error')); } }); } /** * Initialize delete account button * @param {AuthClient} authClient - AuthClient instance */ function initDeleteAccountButton(authClient) { const deleteButton = document.getElementById('delete-account-button'); if (!deleteButton) return; deleteButton.addEventListener('click', async () => { try { const { default: PfDialog } = await import('./components/pf-dialog.js'); const confirmed = await PfDialog.confirm( 'Are you sure you want to delete your account? This action cannot be undone.', 'Delete Account', null, null, 'Delete', 'Cancel' ); if (confirmed) { // Show loading state deleteButton.textContent = 'Deleting...'; deleteButton.disabled = true; // Delete account const result = await authClient.deleteAccount(); console.log('Account deleted successfully:', result); // Show success message await PfDialog.alert('Your account has been deleted successfully.'); // Redirect to home page window.router.navigate('/'); } } catch (error) { console.error('Error deleting account:', error); // Reset button state deleteButton.textContent = 'Delete Account'; deleteButton.disabled = false; // Show error message const { default: PfDialog } = await import('./components/pf-dialog.js'); PfDialog.alert('Error deleting account: ' + (error.message || 'Unknown error')); } }); } /** * Create AuthClient instance * @returns {Promise<AuthClient>} - AuthClient instance */ async function createAuthClient() { try { // Fetch Supabase configuration from the server const configResponse = await fetch('/api/1/config/supabase'); if (!configResponse.ok) { throw new Error('Failed to fetch Supabase configuration'); } const { supabaseUrl, supabaseAnonKey, jwtSecret } = await configResponse.json(); // Create subscription API const subscriptionApi = { /** * Check subscription status * @param {string} email - User email * @returns {Promise<Object>} - Subscription status */ async checkSubscriptionStatus(email) { const response = await fetch(`/api/1/subscriptions/status?email=${encodeURIComponent(email)}`, { headers: { 'Authorization': `Bearer ${localStorage.getItem('jwt_token')}` } }); if (!response.ok) { throw new Error('Failed to check subscription status'); } return await response.json(); }, /** * Create subscription * @param {string} email - User email * @param {string} plan - Subscription plan * @param {string} paymentMethod - Payment method * @returns {Promise<Object>} - Subscription result */ async createSubscription(email, plan, paymentMethod) { const response = await fetch('/api/1/subscriptions/create', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${localStorage.getItem('jwt_token')}` }, body: JSON.stringify({ email, plan, payment_method: paymentMethod }) }); if (!response.ok) { throw new Error('Failed to create subscription'); } return await response.json(); } }; // Create AuthClient return new AuthClient({ supabaseUrl, supabaseKey: supabaseAnonKey, jwtSecret, subscriptionApi, onAuthChanged: (authenticated, user) => { console.log('Auth state changed:', authenticated, user); // You can update UI elements here based on auth state } }); } catch (error) { console.error('Error creating AuthClient:', error); throw error; } }