11import "./style.scss" ;
2+ import fsOperation from "fileSystem" ;
23import toast from "components/toast" ;
4+ import confirm from "dialogs/confirm" ;
5+ import loader from "dialogs/loader" ;
36import Ref from "html-tag-js/ref" ;
47import actionStack from "lib/actionStack" ;
58import auth , { loginEvents } from "lib/auth" ;
69import config from "lib/config" ;
10+ import helpers from "utils/helpers" ;
11+ import Url from "utils/Url" ;
712
813/**
914 * @typedef {object } SideBar
@@ -98,56 +103,66 @@ function create($container, $toggler) {
98103 show ( ) ;
99104 }
100105
101- loginEvents . on ( ( ) => {
102- updateSidebarAvatar ( ) ;
103- } ) ;
106+ loginEvents . addListener ( updateSidebarAvatar ) ;
104107
105108 async function handleUserIconClick ( e ) {
106109 try {
107- const user = await auth . getLoggedInUser ( ) ;
110+ loader . create ( strings [ "login" ] , strings [ "loading..." ] ) ;
111+ let user = await auth . getLoggedInUser ( ) ;
108112
109113 if ( ! user ) {
110- CustomTabs . open (
111- `${ config . BASE_URL } /login?redirect=app` ,
112- { showTitle : true } ,
113- ( ) => { } ,
114- ( ) => { } ,
114+ const confirmation = await confirm (
115+ strings . confirm ,
116+ strings [ "confirm-login" ] ,
115117 ) ;
116- } else {
117- const menu = userContextMenu . el ;
118- const isActive = menu . classList . toggle ( "active" ) ;
119-
120- if ( isActive ) {
121- const menuName = userContextMenu . el . querySelector ( ".user-menu-name" ) ;
122- const menuEmail =
123- userContextMenu . el . querySelector ( ".user-menu-email" ) ;
124-
125- if ( menuName ) {
126- menuName . content = (
127- < div style = { { display : "flex" } } >
128- { Boolean ( user . verified ) && (
129- < span className = "icon verified" > </ span >
130- ) }
131- { user . name }
132- { Boolean ( user . acode_pro ) && < span className = "badge" > Pro</ span > }
133- </ div >
134- ) ;
135- }
136118
137- if ( menuEmail ) {
138- menuEmail . textContent = user . email || "" ;
139- }
119+ if ( ! confirmation ) {
120+ return ;
121+ }
140122
141- setTimeout ( ( ) => {
142- document . addEventListener ( "click" , handleClickOutside ) ;
143- } , 10 ) ;
144- } else {
145- document . removeEventListener ( "click" , handleClickOutside ) ;
123+ loader . show ( ) ;
124+
125+ await auth . login ( ) ;
126+ user = await auth . getLoggedInUser ( ) ;
127+ if ( ! user ) {
128+ return ;
146129 }
147130 }
131+
132+ const menu = userContextMenu . el ;
133+ const isActive = menu . classList . toggle ( "active" ) ;
134+
135+ if ( isActive ) {
136+ const menuName = userContextMenu . el . querySelector ( ".user-menu-name" ) ;
137+ const menuEmail = userContextMenu . el . querySelector ( ".user-menu-email" ) ;
138+
139+ if ( menuName ) {
140+ menuName . content = (
141+ < div style = { { display : "flex" } } >
142+ { user . name }
143+ { Boolean ( user . verified ) && (
144+ < span className = "icon verified badge" > </ span >
145+ ) }
146+ { Boolean ( user . acode_pro ) && < span className = "badge" > Pro</ span > }
147+ </ div >
148+ ) ;
149+ }
150+
151+ if ( menuEmail ) {
152+ menuEmail . textContent = user . email || "" ;
153+ }
154+
155+ setTimeout ( ( ) => {
156+ document . addEventListener ( "click" , handleClickOutside ) ;
157+ } , 10 ) ;
158+ } else {
159+ document . removeEventListener ( "click" , handleClickOutside ) ;
160+ }
148161 } catch ( error ) {
149162 console . error ( "Error checking login status:" , error ) ;
150163 toast ( "Error checking login status" , 3000 ) ;
164+ } finally {
165+ loader . destroy ( ) ;
151166 }
152167 }
153168
@@ -163,47 +178,84 @@ function create($container, $toggler) {
163178 }
164179
165180 async function handleLogout ( ) {
181+ loader . create ( strings [ "logout" ] , strings [ "loading..." ] ) ;
182+ loader . show ( ) ;
166183 try {
184+ const user = await auth . getLoggedInUser ( ) ;
167185 const success = await auth . logout ( ) ;
168186 if ( success ) {
169187 userContextMenu . el . classList . remove ( "active" ) ;
170188 document . removeEventListener ( "click" , handleClickOutside ) ;
171- toast ( "Logged out successfully" ) ;
172189 updateSidebarAvatar ( ) ;
190+ toast ( "Logged out successfully" ) ;
191+
192+ try {
193+ const avatarFile = await getUserAvatar ( user , false ) ;
194+ if ( avatarFile ) {
195+ await fsOperation ( avatarFile ) . delete ( ) ;
196+ }
197+ } catch { }
173198 } else {
174199 toast ( "Failed to logout" ) ;
175200 }
176201 } catch ( error ) {
177202 console . error ( "Error during logout:" , error ) ;
203+ } finally {
204+ loader . destroy ( ) ;
178205 }
179206 }
180207
181208 async function updateSidebarAvatar ( ) {
182- const existingIcon = userAvatar . el . querySelector ( ". icon" ) ;
183- const existingAvatar = userAvatar . el . querySelector ( ".avatar" ) ;
209+ const defaultAvatar = < span className = " icon account_circle" /> ;
210+ const user = await auth . getLoggedInUser ( ) ;
184211
185- if ( existingIcon ) {
186- existingIcon . remove ( ) ;
212+ userAvatar . content = defaultAvatar ;
213+
214+ if ( ! user ) {
215+ return ;
187216 }
188- if ( existingAvatar ) {
189- existingAvatar . remove ( ) ;
217+
218+ defaultAvatar . classList . add ( "loading" ) ;
219+
220+ const img = < img alt = "User avatar" className = "avatar" /> ;
221+ const avatarFile = await getUserAvatar ( user ) ;
222+
223+ img . src = avatarFile
224+ ? await helpers . toInternalUri ( avatarFile )
225+ : generateInitialsAvatar ( user . name ) ;
226+ img . onload = ( ) => defaultAvatar . replaceWith ( img ) ;
227+ }
228+
229+ async function getUserAvatar ( user , download = true ) {
230+ let avatarUrl = user . avatar_url ;
231+
232+ if ( ! avatarUrl ) {
233+ if ( ! user . github ) {
234+ return null ;
235+ }
236+ avatarUrl = `https://avatars.githubusercontent.com/${ user . github } ` ;
190237 }
191238
192- const user = await auth . getLoggedInUser ( ) ;
239+ const hash = avatarUrl . hashCode ( ) ;
240+ const cacheFileName = `user_avatar_${ hash } ` ;
241+ const cacheFile = Url . join ( CACHE_STORAGE , cacheFileName ) ;
193242
194- if ( user ) {
195- const avatarUrl = user . github
196- ? `https://avatars.githubusercontent.com/${ user . github } `
197- : generateInitialsAvatar ( user . name ) ;
198- const avatarImg = document . createElement ( "img" ) ;
199- avatarImg . className = "avatar" ;
200- avatarImg . src = avatarUrl ;
201- userAvatar . append ( avatarImg ) ;
202- } else {
203- const defaultIcon = document . createElement ( "span" ) ;
204- defaultIcon . className = "icon account_circle" ;
205- userAvatar . append ( defaultIcon ) ;
243+ if ( ! ( await fsOperation ( cacheFile ) . exists ( ) ) ) {
244+ if ( ! download ) {
245+ return null ;
246+ }
247+
248+ const blob = await helpers . promisify (
249+ cordova . plugin . http . sendRequest ,
250+ avatarUrl ,
251+ {
252+ responseType : "blob" ,
253+ } ,
254+ ) ;
255+ await fsOperation ( CACHE_STORAGE ) . createFile ( cacheFileName , blob . data ) ;
206256 }
257+
258+ return cacheFile ;
207259 }
208260
209261 function generateInitialsAvatar ( name ) {
0 commit comments