Skip to content

Commit b6f3ee4

Browse files
authored
Merge pull request #100 from billilge/feat/#99-inapp-login
[Feat/#99] 인앱에서 로그인 시 모달 처리
2 parents 841cf39 + 07d8a7d commit b6f3ee4

File tree

3 files changed

+116
-30
lines changed

3 files changed

+116
-30
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
"next-auth": "^5.0.0-beta.19",
4444
"next-pwa": "^5.6.0",
4545
"react": "^18",
46+
"react-device-detect": "^2.2.3",
4647
"react-dom": "^18",
4748
"react-hot-toast": "^2.5.2",
4849
"react-router-dom": "^6.24.0",

src/app/mobile/sign-in/page.tsx

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,102 @@
22

33
import ImageLoginLogo from 'public/assets/images/image-login-logo.svg';
44
import IconGoogle from 'public/assets/icons/icon-google.svg';
5-
import { useEffect } from 'react';
5+
import { useEffect, useState } from 'react';
66
import { useRouter } from 'next/navigation';
7+
import { getUA } from 'react-device-detect';
8+
import Alert from '@/components/mobile/Alert';
79

810
export 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 (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
28+
const safariUrl = `safari://${targetUrl.replace(/https?:\/\//i, '')}`;
29+
window.location.href = safariUrl;
30+
} else {
31+
window.location.href = `intent://${targetUrl.replace(
32+
/https?:\/\//i,
33+
'',
34+
)}#Intent;scheme=http;package=com.android.chrome;end`;
35+
}
36+
};
37+
38+
if (/kakaotalk/i.test(userAgent)) {
39+
window.location.href = `kakaotalk://web/openExternal?url=${encodeURIComponent(
40+
'https://billilge.site/mobile/sign-in',
41+
)}`;
42+
} else if (/line/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+
/inapp|snapchat|wirtschaftswoche|thunderbird|instagram|everytimeapp|whatsApp|electron|wadiz|aliapp|zumapp|iphone.*whale|android.*whale|kakaostory|band|twitter|DaumApps|DaumDevice\/mobile|FB_IAB|FB4A|FBAN|FBIOS|FBSS|trill\/[^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+
/inapp|KAKAOTALK|FBAV|Line|Instagram|wadiz|kakaostory|band|twitter|DaumApps|everytimeapp|whatsApp|electron|aliapp|zumapp|iphone.*whale|android.*whale|DaumDevice\/mobile|FB_IAB|FB4A|FBAN|FBIOS|FBSS|trill/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
}

yarn.lock

Lines changed: 15 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7409,6 +7409,13 @@ randombytes@^2.1.0:
74097409
dependencies:
74107410
safe-buffer "^5.1.0"
74117411

7412+
react-device-detect@^2.2.3:
7413+
version "2.2.3"
7414+
resolved "https://registry.yarnpkg.com/react-device-detect/-/react-device-detect-2.2.3.tgz#97a7ae767cdd004e7c3578260f48cf70c036e7ca"
7415+
integrity sha512-buYY3qrCnQVlIFHrC5UcUoAj7iANs/+srdkwsnNjI7anr3Tt7UY6MqNxtMLlr0tMBied0O49UZVK8XKs3ZIiPw==
7416+
dependencies:
7417+
ua-parser-js "^1.0.33"
7418+
74127419
react-dom@^18:
74137420
version "18.3.1"
74147421
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
@@ -8098,16 +8105,7 @@ string-length@^4.0.1:
80988105
char-regex "^1.0.2"
80998106
strip-ansi "^6.0.0"
81008107

8101-
"string-width-cjs@npm:string-width@^4.2.0":
8102-
version "4.2.3"
8103-
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
8104-
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
8105-
dependencies:
8106-
emoji-regex "^8.0.0"
8107-
is-fullwidth-code-point "^3.0.0"
8108-
strip-ansi "^6.0.1"
8109-
8110-
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
8108+
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
81118109
version "4.2.3"
81128110
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
81138111
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -8218,14 +8216,7 @@ stringify-object@^3.3.0:
82188216
is-obj "^1.0.1"
82198217
is-regexp "^1.0.0"
82208218

8221-
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
8222-
version "6.0.1"
8223-
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
8224-
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
8225-
dependencies:
8226-
ansi-regex "^5.0.1"
8227-
8228-
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
8219+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
82298220
version "6.0.1"
82308221
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
82318222
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -8665,6 +8656,11 @@ typescript@^5:
86658656
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.3.tgz#919b44a7dbb8583a9b856d162be24a54bf80073e"
86668657
integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==
86678658

8659+
ua-parser-js@^1.0.33:
8660+
version "1.0.40"
8661+
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.40.tgz#ac6aff4fd8ea3e794a6aa743ec9c2fc29e75b675"
8662+
integrity sha512-z6PJ8Lml+v3ichVojCiB8toQJBuwR42ySM4ezjXIqXK3M0HczmKQ3LF4rhU55PfD99KEEXQG6yb7iOMyvYuHew==
8663+
86688664
unbox-primitive@^1.1.0:
86698665
version "1.1.0"
86708666
resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2"
@@ -9117,16 +9113,7 @@ [email protected], workbox-window@^6.5.4:
91179113
"@types/trusted-types" "^2.0.2"
91189114
workbox-core "6.6.1"
91199115

9120-
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
9121-
version "7.0.0"
9122-
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
9123-
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
9124-
dependencies:
9125-
ansi-styles "^4.0.0"
9126-
string-width "^4.1.0"
9127-
strip-ansi "^6.0.0"
9128-
9129-
wrap-ansi@^7.0.0:
9116+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
91309117
version "7.0.0"
91319118
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
91329119
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==

0 commit comments

Comments
 (0)