1- import fsOperation from "fileSystem" ;
21import toast from "components/toast" ;
32import { addIntentHandler } from "handlers/intent" ;
4- import constants from "./constants" ;
53
64const loginEvents = {
75 listeners : new Set ( ) ,
@@ -18,70 +16,16 @@ const loginEvents = {
1816 } ,
1917} ;
2018
21- async function checkTokenFileExists ( ) {
22- return await fsOperation ( `${ DATA_STORAGE } .acode_token` ) . exists ( ) ;
23- }
24-
25- async function saveToken ( token ) {
26- try {
27- if ( await checkTokenFileExists ( ) ) {
28- await fsOperation ( `${ DATA_STORAGE } .acode_token` ) . writeFile ( token ) ;
29- } else {
30- await fsOperation ( DATA_STORAGE ) . createFile ( ".acode_token" , token ) ;
31- }
32- return true ;
33- } catch ( error ) {
34- console . error ( "Failed to save token" , error ) ;
35- return false ;
36- }
37- }
38-
39- async function getToken ( ) {
40- try {
41- if ( await checkTokenFileExists ( ) ) {
42- const token = await fsOperation ( `${ DATA_STORAGE } .acode_token` ) . readFile (
43- "utf8" ,
44- ) ;
45- return token ;
46- }
47- return null ;
48- } catch ( error ) {
49- console . error ( "Failed to get token" , error ) ;
50- return null ;
51- }
52- }
53-
54- async function deleteToken ( ) {
55- try {
56- if ( await checkTokenFileExists ( ) ) {
57- await fsOperation ( `${ DATA_STORAGE } .acode_token` ) . delete ( ) ;
58- return true ;
59- }
60- return false ;
61- } catch ( error ) {
62- console . error ( "Failed to delete token" , error ) ;
63- return false ;
64- }
65- }
66-
6719class AuthService {
6820 constructor ( ) {
6921 addIntentHandler ( this . onIntentReceiver . bind ( this ) ) ;
7022 }
7123
72- openLoginUrl ( ) {
73- try {
74- system . openInBrowser ( "https://acode.app/login?redirect=app" ) ;
75- } catch ( error ) {
76- console . error ( "Failed while opening login page." , error ) ;
77- }
78- }
79-
8024 async onIntentReceiver ( event ) {
8125 try {
8226 if ( event ?. module === "user" && event ?. action === "login" ) {
8327 if ( event ?. value ) {
84- saveToken ( event . value ) ;
28+ this . _exec ( "saveToken" , [ event . value ] ) ;
8529 toast ( "Logged in successfully" ) ;
8630
8731 setTimeout ( ( ) => {
@@ -96,10 +40,32 @@ class AuthService {
9640 }
9741 }
9842
43+ /**
44+ * Helper to wrap cordova.exec in a Promise
45+ */
46+ _exec ( action , args = [ ] ) {
47+ return new Promise ( ( resolve , reject ) => {
48+ cordova . exec ( resolve , reject , "Authenticator" , action , args ) ;
49+ } ) ;
50+ }
51+
52+ async openLoginUrl ( ) {
53+ const url = "https://acode.app/login?redirect=app" ;
54+
55+ try {
56+ await new Promise ( ( resolve , reject ) => {
57+ CustomTabs . open ( url , { showTitle : true } , resolve , reject ) ;
58+ } ) ;
59+ } catch ( error ) {
60+ console . error ( "CustomTabs failed, opening system browser." , error ) ;
61+ system . openInBrowser ( url ) ;
62+ }
63+ }
64+
9965 async logout ( ) {
10066 try {
101- const result = await deleteToken ( ) ;
102- return result ;
67+ await this . _exec ( "logout" ) ;
68+ return true ;
10369 } catch ( error ) {
10470 console . error ( "Failed to logout." , error ) ;
10571 return false ;
@@ -108,69 +74,20 @@ class AuthService {
10874
10975 async isLoggedIn ( ) {
11076 try {
111- const token = await getToken ( ) ;
112- if ( ! token ) return false ;
113-
114- return new Promise ( ( resolve , reject ) => {
115- cordova . plugin . http . sendRequest (
116- `${ constants . API_BASE } /login` ,
117- {
118- method : "GET" ,
119- headers : {
120- "x-auth-token" : token ,
121- } ,
122- } ,
123- ( response ) => {
124- resolve ( true ) ;
125- } ,
126- async ( error ) => {
127- if ( error . status === 401 ) {
128- await deleteToken ( ) ;
129- resolve ( false ) ;
130- } else {
131- console . error ( "Failed to check login status." , error ) ;
132- resolve ( false ) ;
133- }
134- } ,
135- ) ;
136- } ) ;
77+ // Native checks EncryptedPrefs and validates with API internally
78+ await this . _exec ( "isLoggedIn" ) ;
79+ return true ;
13780 } catch ( error ) {
138- console . error ( "Failed to check login status." , error ) ;
81+ console . error ( error ) ;
82+ // error is typically the status code (0 if no token, 401 if invalid)
13983 return false ;
14084 }
14185 }
14286
14387 async getUserInfo ( ) {
14488 try {
145- const token = await getToken ( ) ;
146- if ( ! token ) return null ;
147-
148- return new Promise ( ( resolve , reject ) => {
149- cordova . plugin . http . sendRequest (
150- `${ constants . API_BASE } /login` ,
151- {
152- method : "GET" ,
153- headers : {
154- "x-auth-token" : token ,
155- } ,
156- } ,
157- async ( response ) => {
158- if ( response . status === 200 ) {
159- resolve ( JSON . parse ( response . data ) ) ;
160- }
161- resolve ( null ) ;
162- } ,
163- async ( error ) => {
164- if ( error . status === 401 ) {
165- await deleteToken ( ) ;
166- resolve ( null ) ;
167- } else {
168- console . error ( "Failed to fetch user data." , error ) ;
169- resolve ( null ) ;
170- }
171- } ,
172- ) ;
173- } ) ;
89+ const data = await this . _exec ( "getUserInfo" ) ;
90+ return typeof data === "string" ? JSON . parse ( data ) : data ;
17491 } catch ( error ) {
17592 console . error ( "Failed to fetch user data." , error ) ;
17693 return null ;
@@ -187,42 +104,7 @@ class AuthService {
187104 }
188105
189106 if ( userData . name ) {
190- const nameParts = userData . name . split ( " " ) ;
191- let initials = "" ;
192-
193- if ( nameParts . length >= 2 ) {
194- initials = `${ nameParts [ 0 ] [ 0 ] } ${ nameParts [ 1 ] [ 0 ] } ` . toUpperCase ( ) ;
195- } else {
196- initials = nameParts [ 0 ] [ 0 ] . toUpperCase ( ) ;
197- }
198-
199- // Create a data URL for text-based avatar
200- const canvas = document . createElement ( "canvas" ) ;
201- canvas . width = 100 ;
202- canvas . height = 100 ;
203- const ctx = canvas . getContext ( "2d" ) ;
204-
205- // Set background
206- // Array of colors to choose from
207- const colors = [
208- "#2196F3" ,
209- "#9C27B0" ,
210- "#E91E63" ,
211- "#009688" ,
212- "#4CAF50" ,
213- "#FF9800" ,
214- ] ;
215- ctx . fillStyle = colors [ Math . floor ( Math . random ( ) * colors . length ) ] ;
216- ctx . fillRect ( 0 , 0 , 100 , 100 ) ;
217-
218- // Add text
219- ctx . fillStyle = "#ffffff" ;
220- ctx . font = "bold 40px Arial" ;
221- ctx . textAlign = "center" ;
222- ctx . textBaseline = "middle" ;
223- ctx . fillText ( initials , 50 , 50 ) ;
224-
225- return canvas . toDataURL ( ) ;
107+ return this . _generateInitialsAvatar ( userData . name ) ;
226108 }
227109
228110 return null ;
@@ -231,6 +113,42 @@ class AuthService {
231113 return null ;
232114 }
233115 }
116+
117+ _generateInitialsAvatar ( name ) {
118+ const nameParts = name . split ( " " ) ;
119+ const initials =
120+ nameParts . length >= 2
121+ ? `${ nameParts [ 0 ] [ 0 ] } ${ nameParts [ 1 ] [ 0 ] } ` . toUpperCase ( )
122+ : nameParts [ 0 ] [ 0 ] . toUpperCase ( ) ;
123+
124+ const canvas = document . createElement ( "canvas" ) ;
125+ canvas . width = 100 ;
126+ canvas . height = 100 ;
127+ const ctx = canvas . getContext ( "2d" ) ;
128+
129+ const colors = [
130+ "#2196F3" ,
131+ "#9C27B0" ,
132+ "#E91E63" ,
133+ "#009688" ,
134+ "#4CAF50" ,
135+ "#FF9800" ,
136+ ] ;
137+ ctx . fillStyle =
138+ colors [
139+ name . split ( "" ) . reduce ( ( acc , char ) => acc + char . charCodeAt ( 0 ) , 0 ) %
140+ colors . length
141+ ] ;
142+ ctx . fillRect ( 0 , 0 , 100 , 100 ) ;
143+
144+ ctx . fillStyle = "#ffffff" ;
145+ ctx . font = "bold 40px Arial" ;
146+ ctx . textAlign = "center" ;
147+ ctx . textBaseline = "middle" ;
148+ ctx . fillText ( initials , 50 , 50 ) ;
149+
150+ return canvas . toDataURL ( ) ;
151+ }
234152}
235153
236154export default new AuthService ( ) ;
0 commit comments