PageSourceSearch

https://rwatimes.io/public/js/alpine/auth.js

js rwatimes.io collected 2026-09-29 04:06:57 UTC 3,497 bytes, 132 lines download raw bytes

1import api from '../api-client.js';
2import {
3	saveAuthData,
4	clearAuthData,
5	saveRefreshToken,
6} from '../auth-storage.js';
7import { ensureDeviceRegistered } from '../device-fp.js';
8import { updateUserProfile } from '../db/repositories/user.repository.js';
9
10document.addEventListener('alpine:init', () => {
11	Alpine.data('auth', () => ({
12		email: '',
13		password: '',
14		loading: false,
15		error: null,
16		successMessage: null,
17
18		init() {
19		},
20
21		async handleSocialLogin(provider) {
22			this.loading = true;
23			this.error = null;
24			try {
25				let result;
26				
27				if (provider === 'google') result = await window.signInWithGoogle();
28				else if (provider === 'facebook')
29					result = await window.signInWithFacebook();
30				else if (provider === 'apple') result = await window.signInWithApple();
31
32				const token = await result.user.getIdToken();
33				await this.signTokenToBackend(token);
34			} catch (err) {
35				this.error = `${provider} Sign In Failed`;
36				console.error(err);
37			} finally {
38				this.loading = false;
39			}
40		},
41
42		async handleEmailLogin(e) {
43			e.preventDefault();
44			this.loading = true;
45			this.error = null;
46			this.successMessage = null;
47
48			// Check for demo accounts
49			if (
50				this.email === '[email protected]' ||
51				this.email === '[email protected]'
52			) {
53				await this.signTokenToBackend(this.email);
54				return;
55			}
56
57			try {
58				const result = await window.loginWithEmailLink(this.email);
59				this.successMessage = result.message;
60			} catch (err) {
61				this.error = err.message || 'Failed to send login link';
62			} finally {
63				this.loading = false;
64			}
65		},
66
67		async handleEmailSignUp(e) {
68			e.preventDefault();
69			this.loading = true;
70			this.error = null;
71			this.successMessage = null;
72
73			try {
74				const result = await window.signUpWithEmailLink(this.email);
75				this.successMessage = result.message;
76			} catch (err) {
77				this.error = err.message || 'Failed to send sign up link';
78			} finally {
79				this.loading = false;
80			}
81		},
82
83		async signTokenToBackend(token) {
84			try {
85				const response = await api.post('/api/auth/login', { token });
86
87				if (response.status === 200 || response.status === 201) {
88					const { user, access_token, refresh_token } = response.data.data;
89
90					// 1. Save data to IDB and Cookies
91					await saveAuthData(user, access_token);
92					
93					if (refresh_token) {
94						await saveRefreshToken(refresh_token);
95					}
96
97					// 2. Register device
98					try {
99						await ensureDeviceRegistered(access_token);
100					} catch (deviceErr) {
101						console.error('Device registration failed:', deviceErr);
102						// We continue anyway, as login was successful
103					}
104
105					// 3. Update global store
106					Alpine.store('app').user = user;
107
108					// 4. Redirect
109					const urlParams = new URLSearchParams(window.location.search);
110					const redirectUrl = urlParams.get('redirect') || '/profile';
111					window.location.href = redirectUrl;
112				}
113			} catch (err) {
114				// No err.response = the failure is client-side (IndexedDB, interceptor,
115				// post-login code) — show the real error instead of a generic message.
116				this.error =
117					err.response?.data?.message || err.message || 'Authentication failed on server';
118				console.error('Sign token to backend error:', err, 'response:', err.response);
119			}
120		},
121
122		async handleLogout() {
123			try {
124				await clearAuthData();
125				Alpine.store('app').user = null;
126				window.location.href = '/login';
127			} catch (err) {
128				console.error('Logout failed:', err);
129			}
130		},
131	}));
132});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.