11import React , { useEffect , useState } from 'react' ;
22import { Notification } from '@jupyterlab/apputils' ;
3+ import {
4+ IconChevronDown ,
5+ IconBrandChrome ,
6+ IconBrandFirefox ,
7+ IconBrandEdge ,
8+ IconBrandSafari ,
9+ IconBrandOpera ,
10+ IconBrandVivaldi ,
11+ IconBrandArc ,
12+ IconWorldWww
13+ } from '@tabler/icons-react' ;
14+ import { Button , Menu , useMantineTheme } from '@mantine/core' ;
315import { getCookie } from '../services/cookie' ;
4- import Bowser from 'bowser' ;
516
6- const BrowserCookie : React . FC < {
7- setCookieLoggedIn : ( b : string ) => void ;
8- } > = ( { setCookieLoggedIn } ) => {
9- const browsers = [
10- 'Chrome' ,
11- 'Firefox' ,
12- 'Safari' ,
13- 'Edge' ,
14- 'Opera' ,
15- 'Brave' ,
16- 'Vivaldi' ,
17- 'Chromium' ,
18- 'Arc' ,
19- 'LibreWolf' ,
20- 'Opera GX'
21- ] ;
17+ const BROWSERS = [
18+ {
19+ name : 'Chrome' ,
20+ icon : ( color : string ) => (
21+ < IconBrandChrome size = { 16 } color = { color } stroke = { 1.5 } />
22+ )
23+ } ,
24+ {
25+ name : 'Firefox' ,
26+ icon : ( color : string ) => (
27+ < IconBrandFirefox size = { 16 } color = { color } stroke = { 1.5 } />
28+ )
29+ } ,
30+ {
31+ name : 'Safari' ,
32+ icon : ( color : string ) => (
33+ < IconBrandSafari size = { 16 } color = { color } stroke = { 1.5 } />
34+ )
35+ } ,
36+ {
37+ name : 'Edge' ,
38+ icon : ( color : string ) => (
39+ < IconBrandEdge size = { 16 } color = { color } stroke = { 1.5 } />
40+ )
41+ } ,
42+ {
43+ name : 'Opera' ,
44+ icon : ( color : string ) => (
45+ < IconBrandOpera size = { 16 } color = { color } stroke = { 1.5 } />
46+ )
47+ } ,
48+ {
49+ name : 'Brave' ,
50+ icon : ( color : string ) => (
51+ < IconWorldWww size = { 16 } color = { color } stroke = { 1.5 } />
52+ )
53+ } ,
54+ {
55+ name : 'Vivaldi' ,
56+ icon : ( color : string ) => (
57+ < IconBrandVivaldi size = { 16 } color = { color } stroke = { 1.5 } />
58+ )
59+ } ,
60+ {
61+ name : 'Chromium' ,
62+ icon : ( color : string ) => (
63+ < IconBrandChrome size = { 16 } color = { color } stroke = { 1.5 } />
64+ )
65+ } ,
66+ {
67+ name : 'Arc' ,
68+ icon : ( color : string ) => (
69+ < IconBrandArc size = { 16 } color = { color } stroke = { 1.5 } />
70+ )
71+ } ,
72+ {
73+ name : 'LibreWolf' ,
74+ icon : ( color : string ) => (
75+ < IconWorldWww size = { 16 } color = { color } stroke = { 1.5 } />
76+ )
77+ } ,
78+ {
79+ name : 'Opera GX' ,
80+ icon : ( color : string ) => (
81+ < IconBrandOpera size = { 16 } color = { color } stroke = { 1.5 } />
82+ )
83+ }
84+ ] ;
2285
23- const normalizeBrowserName = ( name : string ) =>
24- name . toLowerCase ( ) . replace ( / \s + / g, '_' ) ;
86+ const normalizeBrowserName = ( name : string ) =>
87+ name . toLowerCase ( ) . replace ( / \s + / g, '_' ) ;
2588
89+ const BrowserCookie : React . FC < {
90+ className ?: string ;
91+ setCookieLoggedIn : ( b : string ) => void ;
92+ } > = ( { className, setCookieLoggedIn } ) => {
2693 const [ browser , setBrowser ] = useState ( '' ) ;
2794 const [ checked , setChecked ] = useState ( false ) ;
2895
29- // set browser value by detecting current browser
3096 useEffect ( ( ) => {
31- const browserName = Bowser . getParser (
32- window . navigator . userAgent
33- ) . getBrowserName ( true ) ;
34- if ( browserName ) {
35- const firstMatch = browsers . find ( b =>
36- new RegExp ( b , 'i' ) . test ( browserName )
37- ) ;
38- if ( firstMatch ) {
39- setBrowser ( normalizeBrowserName ( firstMatch ) ) ;
40- }
41- }
42- } , [ ] ) ;
43-
44- useEffect ( ( ) => {
45- if ( checked ) {
46- setCookieLoggedIn ( browser ) ;
47- }
48- } , [ checked , setCookieLoggedIn ] ) ;
49-
50- const checkCookie = ( ) => {
5197 if ( ! browser ) {
52- Notification . error ( 'Please select a browser.' , { autoClose : 3000 } ) ;
5398 return ;
5499 }
55100 if ( browser === 'safari' ) {
@@ -62,37 +107,56 @@ const BrowserCookie: React.FC<{
62107
63108 getCookie ( browser )
64109 . then ( resp => {
110+ if ( ! resp [ 'checked' ] ) {
111+ Notification . error (
112+ `Failed to check cookie for ${ browser } . Please ensure you are logged in to LeetCode in this browser.` ,
113+ { autoClose : 3000 }
114+ ) ;
115+ }
65116 setChecked ( resp [ 'checked' ] ) ;
66117 } )
67118 . catch ( e => Notification . error ( e . message , { autoClose : 3000 } ) ) ;
68- } ;
119+ } , [ browser ] ) ;
120+
121+ useEffect ( ( ) => {
122+ if ( checked ) {
123+ setCookieLoggedIn ( browser ) ;
124+ }
125+ } , [ checked ] ) ;
69126
127+ const theme = useMantineTheme ( ) ;
70128 return (
71- < div >
72- < label htmlFor = "browser-selector" >
73- Choose your browser that has LeetCode logged in:
74- </ label >
75- < select
76- id = "browser-selector"
77- required
78- value = { browser }
79- onChange = { e => setBrowser ( e . target . value ) }
80- >
81- < option value = "" disabled >
82- Select a browser
83- </ option >
84- { browsers . map ( browser => (
85- < option
86- key = { browser . toLowerCase ( ) }
87- value = { normalizeBrowserName ( browser ) }
129+ < Menu
130+ transitionProps = { { transition : 'pop-top-right' } }
131+ position = "bottom-end"
132+ width = { 220 }
133+ withinPortal
134+ radius = "md"
135+ >
136+ < Menu . Target >
137+ < Button
138+ rightSection = { < IconChevronDown size = { 18 } stroke = { 1.5 } /> }
139+ pr = { 12 }
140+ radius = "md"
141+ size = "md"
142+ className = { className }
143+ >
144+ Load from browser
145+ </ Button >
146+ </ Menu . Target >
147+ < Menu . Dropdown >
148+ < Menu . Label > With LeetCode logged in</ Menu . Label >
149+ { BROWSERS . map ( ( { name, icon } , i ) => (
150+ < Menu . Item
151+ key = { name }
152+ leftSection = { icon ( theme . colors . blue [ 6 ] ) }
153+ onClick = { ( ) => setBrowser ( normalizeBrowserName ( name ) ) }
88154 >
89- { browser }
90- </ option >
155+ { name }
156+ </ Menu . Item >
91157 ) ) }
92- </ select >
93- < button onClick = { checkCookie } > Check</ button >
94- < p > Checked: { checked ? 'Yes' : 'No' } </ p >
95- </ div >
158+ </ Menu . Dropdown >
159+ </ Menu >
96160 ) ;
97161} ;
98162
0 commit comments