diff --git a/.env.development b/.env.development index 5f27b423b..7744277c4 100644 --- a/.env.development +++ b/.env.development @@ -9,6 +9,6 @@ NEXT_PUBLIC_AMPLITUDE_API_KEY= NEXT_PUBLIC_KAKAO_TALK_PLUGIN_KEY= NEXT_PUBLIC_ADMIN_API_URL=https://api-dev-api.sopt.org/v2 NEXT_PUBLIC_ADMIN_API_KEY= +NEXT_PUBLIC_AUTH_API_URL=https://auth-dev-api.sopt.org NEXT_PUBLIC_OPERATION_API_URL=https://operation-api-dev.sopt.org -NEXT_PUBLIC_AUTH_API_URL=https://auth-api-dev.sopt.org -NEXT_PUBLIC_CREW_API_URL=https://crew-dev.sopt.org \ No newline at end of file +NEXT_PUBLIC_CREW_API_URL=https://crew-dev.sopt.org diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6225c31ad..db74ceec2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -41,9 +41,15 @@ jobs: - name: Build run: yarn build && yarn next export + - name: Prepare deployment package + run: | + mkdir -p deploy + cp -r out/* deploy/ + cp -r functions deploy/ + - uses: actions/upload-artifact@v4 with: name: built-app - path: out + path: deploy if-no-files-found: error retention-days: 7 diff --git a/functions/.well-known/apple-app-site-association.ts b/functions/.well-known/apple-app-site-association.ts new file mode 100644 index 000000000..8a6a4fdc1 --- /dev/null +++ b/functions/.well-known/apple-app-site-association.ts @@ -0,0 +1,19 @@ +const APPLE_APP_SITE_ASSOCIATION = `{ + "applinks": { + "apps": [], + "details": [ + { + "appID": "95YWTT5L8K.com.sopt-stamp-iOS.release", + "paths": ["*"] + } + ] + } +}`; + +export const onRequest: PagesFunction = () => { + return new Response(APPLE_APP_SITE_ASSOCIATION, { + headers: { + 'Content-Type': 'application/json', + }, + }); +}; diff --git a/functions/.well-known/assetlinks.json.ts b/functions/.well-known/assetlinks.json.ts new file mode 100644 index 000000000..5bf7edac8 --- /dev/null +++ b/functions/.well-known/assetlinks.json.ts @@ -0,0 +1,21 @@ +const ASSETLINKS_JSON = `[ + { + "relation": ["delegate_permission/common.handle_all_urls"], + "target": { + "namespace": "android_app", + "package_name": "org.sopt.official", + "sha256_cert_fingerprints": [ + "29:23:1F:E3:7A:FD:76:9C:58:CA:F3:E2:D9:7C:A1:69:CF:04:A8:6E:5B:8A:C6:56:6A:6F:E8:FD:D8:FF:47:43", + "30:8A:35:1F:E1:88:94:6F:BC:E9:B2:D5:FC:2F:9B:F2:10:35:2A:43:B8:36:03:8B:C4:1B:EA:51:23:76:1C:00" + ] + } + } +]`; + +export const onRequest: PagesFunction = () => { + return new Response(ASSETLINKS_JSON, { + headers: { + 'Content-Type': 'application/json', + }, + }); +}; diff --git a/public/.well-known/apple-app-site-association b/public/.well-known/apple-app-site-association index 0ccf0bd8b..8d57ce1d8 100644 --- a/public/.well-known/apple-app-site-association +++ b/public/.well-known/apple-app-site-association @@ -1,20 +1,13 @@ -{\rtf1\ansi\ansicpg1252\cocoartf2822 -\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\froman\fcharset0 Times-Roman;} -{\colortbl;\red255\green255\blue255;\red0\green0\blue0;} -{\*\expandedcolortbl;;\cssrgb\c0\c0\c0;} -\paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0 -\deftab720 -\pard\pardeftab720\partightenfactor0 - -\f0\fs24 \cf0 \expnd0\expndtw0\kerning0 -\{\ - \'93applinks\'94: \{\ - \'93apps\'94: [],\ - \'93details\'94: [\ - \{\ - \'93appID\'94: \'9395YWTT5L8K.com.sopt-stamp-iOS.release\'94,\ - \'93paths\'94: [\'93*\'94]\ - \}\ - ]\ - \}\ -\}} \ No newline at end of file +{ + "applinks": { + "apps": [], + "details": [ + { + "appID": "95YWTT5L8K.com.sopt-stamp-iOS.release", + "paths": [ + "*" + ] + } + ] + } +} diff --git a/src/api/index.ts b/src/api/index.ts index 7a43607b3..de8136ed6 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -95,12 +95,17 @@ export const handleTokenError = async (error: AxiosError) => { // 개인정보 처리방침 페이지는 로그인 필요 없음, 구글 정책상 오픈 return Promise.reject(error); } + // 앱 딥링크를 위한 .well-known 경로는 인증 체크 제외 + if (window.location.pathname.startsWith('/.well-known')) { + return Promise.reject(error); + } /** 토큰이 없으면 refresh 시도하지 않고 바로 intro로 이동 */ const currentToken = tokenStorage.get(); if (currentToken === null && window.location.pathname !== '/intro') { window.location.replace('/intro'); throw new Error('토큰이 없습니다.'); } + try { const { data } = await axiosAuthInstance.post<{ data: { accessToken: string } }>( `/api/v1/auth/refresh/web`, diff --git a/src/components/members/main/MemberList/index.tsx b/src/components/members/main/MemberList/index.tsx index e840637b6..d12fff1a5 100644 --- a/src/components/members/main/MemberList/index.tsx +++ b/src/components/members/main/MemberList/index.tsx @@ -4,6 +4,7 @@ import { colors } from '@sopt-makers/colors'; import { fonts } from '@sopt-makers/fonts'; import { IconSwitchVertical } from '@sopt-makers/icons'; import { SearchField } from '@sopt-makers/ui'; +import { Spacing } from '@toss/emotion-utils'; import { debounce, uniq } from 'lodash-es'; import Link from 'next/link'; import { useRouter } from 'next/router'; @@ -45,7 +46,6 @@ import { useRunOnce } from '@/hooks/useRunOnce'; import IconDiagonalArrow from '@/public/icons/icon-diagonal-arrow.svg'; import { MB_BIG_MEDIA_QUERY } from '@/styles/mediaQuery'; import { MOBILE_MEDIA_QUERY } from '@/styles/mediaQuery'; -import { Spacing } from '@toss/emotion-utils'; const PAGE_LIMIT = 24; interface MemberListProps { @@ -492,7 +492,7 @@ const MemberList: FC = ({ banner }) => { const badges = sorted .filter((activity) => activity.generation && activity.part) .map((activity) => ({ - content: `${activity.generation}기 ${activity.part}`, + content: `${activity.generation}기 ${activity.team || activity.part}`, isActive: activity.generation === LATEST_GENERATION, }));