22
33import ImageLoginLogo from 'public/assets/images/image-login-logo.svg' ;
44import IconGoogle from 'public/assets/icons/icon-google.svg' ;
5- import { useEffect } from 'react' ;
5+ import { useEffect , useState } from 'react' ;
66import { useRouter } from 'next/navigation' ;
7+ import { getUA } from 'react-device-detect' ;
8+ import Alert from '@/components/mobile/Alert' ;
79
810export default function SignIn ( ) {
911 const router = useRouter ( ) ;
12+ const [ alertState , setAlertState ] = useState ( false ) ;
13+
14+ const handleAlertOpen = ( ) => {
15+ setAlertState ( true ) ;
16+ } ;
17+
18+ const handleAlertClose = ( ) => {
19+ setAlertState ( false ) ;
20+ } ;
21+
22+ const handleInAppBrowser = ( ) => {
23+ const userAgent = navigator . userAgent . toLowerCase ( ) ;
24+ const redirectToExternalBrowser = ( ) => {
25+ const targetUrl = 'https://billilge.site/mobile/sign-in' ;
26+
27+ if ( / i P h o n e | i P a d | i P o d / i. test ( navigator . userAgent ) ) {
28+ const safariUrl = `safari://${ targetUrl . replace ( / h t t p s ? : \/ \/ / i, '' ) } ` ;
29+ window . location . href = safariUrl ;
30+ } else {
31+ window . location . href = `intent://${ targetUrl . replace (
32+ / h t t p s ? : \/ \/ / i,
33+ '' ,
34+ ) } #Intent;scheme=http;package=com.android.chrome;end`;
35+ }
36+ } ;
37+
38+ if ( / k a k a o t a l k / i. test ( userAgent ) ) {
39+ window . location . href = `kakaotalk://web/openExternal?url=${ encodeURIComponent (
40+ 'https://billilge.site/mobile/sign-in' ,
41+ ) } `;
42+ } else if ( / l i n e / i. test ( userAgent ) ) {
43+ const targetUrl = 'https://billilge.site/mobile/sign-in' ;
44+ window . location . href = targetUrl . includes ( '?' )
45+ ? `${ targetUrl } &openExternalBrowser=1`
46+ : `${ targetUrl } ?openExternalBrowser=1` ;
47+ } else if (
48+ / i n a p p | s n a p c h a t | w i r t s c h a f t s w o c h e | t h u n d e r b i r d | i n s t a g r a m | e v e r y t i m e a p p | w h a t s A p p | e l e c t r o n | w a d i z | a l i a p p | z u m a p p | i p h o n e .* w h a l e | a n d r o i d .* w h a l e | k a k a o s t o r y | b a n d | t w i t t e r | D a u m A p p s | D a u m D e v i c e \/ m o b i l e | F B _ I A B | F B 4 A | F B A N | F B I O S | F B S S | t r i l l \/ [ ^ 1 ] / i. test (
49+ userAgent ,
50+ )
51+ ) {
52+ redirectToExternalBrowser ( ) ;
53+ }
54+ } ;
1055
1156 const handleLogin = ( ) => {
12- window . location . href = `${ process . env . NEXT_PUBLIC_API_BASE_URI } /oauth2/authorization/google` ;
57+ if (
58+ getUA . match (
59+ / i n a p p | K A K A O T A L K | F B A V | L i n e | I n s t a g r a m | w a d i z | k a k a o s t o r y | b a n d | t w i t t e r | D a u m A p p s | e v e r y t i m e a p p | w h a t s A p p | e l e c t r o n | a l i a p p | z u m a p p | i p h o n e .* w h a l e | a n d r o i d .* w h a l e | D a u m D e v i c e \/ m o b i l e | F B _ I A B | F B 4 A | F B A N | F B I O S | F B S S | t r i l l / i,
60+ )
61+ ) {
62+ handleAlertOpen ( ) ;
63+ } else {
64+ window . location . href = `${ process . env . NEXT_PUBLIC_API_BASE_URI } /oauth2/authorization/google` ;
65+ }
66+ } ;
67+
68+ const alertConfirmText =
69+ '인앱 브라우저는 구글 로그인을 \n사용할 수 없습니다.' ;
70+
71+ const copyToClipboard = async ( text : string ) => {
72+ if ( navigator . clipboard && window . isSecureContext ) {
73+ try {
74+ await navigator . clipboard . writeText ( text ) ;
75+ } catch ( e ) {
76+ alert ( '복사에 실패했습니다. 다시 시도해주세요.' ) ;
77+ }
78+ } else {
79+ // navigator.clipboard가 사용 불가능한 경우
80+ const textArea = document . createElement ( 'textarea' ) ;
81+ textArea . value = text ;
82+ textArea . style . position = 'fixed' ;
83+ textArea . style . left = '-9999px' ;
84+ document . body . appendChild ( textArea ) ;
85+ textArea . focus ( ) ;
86+ textArea . select ( ) ;
87+
88+ try {
89+ document . execCommand ( 'copy' ) ;
90+ } catch ( e ) {
91+ alert ( '복사에 실패했습니다. 다시 시도해주세요.' ) ;
92+ } finally {
93+ document . body . removeChild ( textArea ) ;
94+ }
95+ }
96+ } ;
97+
98+ const handleAlertConfirm = async ( ) => {
99+ handleInAppBrowser ( ) ;
100+ copyToClipboard ( 'https://billilge.site/mobile/sign-in' ) ;
13101 } ;
14102
15103 useEffect ( ( ) => {
@@ -36,6 +124,16 @@ export default function SignIn() {
36124 < div className = "flex font-medium" > Google로 시작하기</ div >
37125 < div className = "h-6 w-6" />
38126 </ button >
127+ { alertState && (
128+ < Alert
129+ content = { alertConfirmText }
130+ isMainColor
131+ ctaButtonText = "URL 복사하기"
132+ otherButtonText = "닫기"
133+ onClickCta = { handleAlertConfirm }
134+ onClickOther = { handleAlertClose }
135+ />
136+ ) }
39137 </ section >
40138 ) ;
41139}
0 commit comments