Skip to content

Commit

Permalink
Merge pull request #247 from boostcampwm-2024/dev-fe
Browse files Browse the repository at this point in the history
[MERGE] dev-fe -> dev 로 병합
  • Loading branch information
hoeeeeeh authored Nov 28, 2024
2 parents 7dc2428 + e32bfe5 commit 88aca02
Show file tree
Hide file tree
Showing 163 changed files with 6,170 additions and 14,675 deletions.
56 changes: 56 additions & 0 deletions .github/workflows/prod-fe-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: Build and Push Docker Image

on:
push:
branches:
- prod-fe

jobs:
build:
name: Build, Test, and Push Docker Image
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '20'

- name: Install dependencies with Yarn
run: yarn install

- name: Build only backend package with Yarn
run: yarn build:fe

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Build and push Docker image
run: |
docker compose -f fe.build.yaml build --no-cache
docker compose -f fe.build.yaml push
env:
DOCKER_BUILDKIT: 1

- name: Execute deployment script on remote server
env:
SSH_PEM_KEY: ${{ secrets.SSH_PEM_KEY }}
SSH_USERNAME: ${{ secrets.SSH_USERNAME }}
SSH_PORT: ${{ secrets.SSH_PORT }}

run: |
mkdir -p ~/.ssh
echo "$SSH_PEM_KEY" > ~/.ssh/SSH_PEM_KEY.pem
chmod 600 ~/.ssh/SSH_PEM_KEY.pem
ssh -p $SSH_PORT -i ~/.ssh/SSH_PEM_KEY.pem -o StrictHostKeyChecking=no [email protected] 'cd prod && bash prod_fe.sh'
14 changes: 14 additions & 0 deletions fe.build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# docker-compose.yml
version: '3.8'

services:
nginx:
build:
context: nginx
dockerfile: dockerfile
image: liboost/nginx:latest
ports:
- "80:80"
- "443:443"
- "8000:8000"
- "1935:1935"
6 changes: 4 additions & 2 deletions frontend/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ export default tseslint.config({ ignores: ['.*'] }, js.configs.recommended, ...t
],
'react/react-in-jsx-scope': 'off',
eqeqeq: ['error', 'always'],
indent: ['error', 2],
indent: ['error', 2, { SwitchCase: 1 }],
quotes: ['error', 'single'],
semi: ['error', 'always'],
'@typescript-eslint/no-unused-vars': ['error']
'@typescript-eslint/no-unused-vars': ['error'],
'@typescript-eslint/no-explicit-any': 'off',
'react/prop-types': 'off'
},
settings: {
...reactRecommended.settings
Expand Down
4 changes: 2 additions & 2 deletions frontend/index.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<html lang="ko">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/pabicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LiBoo 🚀</title>
</head>
Expand Down
7 changes: 7 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,19 @@
"@vitejs/plugin-react": "^4.3.3",
"axios": "^1.7.7",
"eslint-plugin-react": "^7.37.2",
"framer-motion": "^11.11.17",
"hls.js": "^1.5.17",
"lucide-react": "^0.461.0",
"nanoid": "^5.0.8",
"react": "^18.3.1",
"react-content-loader": "^7.0.2",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.1.2",
"react-hook-form": "^7.53.2",
"react-router-dom": "^6.27.0",
"socket.io-client": "^4.8.1",
"styled-components": "^6.1.13",
"ts-pattern": "^5.5.0",
"vite": "^5.4.10",
"vite-plugin-svgr": "^4.3.0",
"vite-tsconfig-paths": "^5.1.0"
Expand Down
Binary file added frontend/public/pabicon.ico
Binary file not shown.
18 changes: 13 additions & 5 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { ThemeProvider } from 'styled-components';

import { theme } from './styles/theme';
import { MainPage, ClientPage, HostPage } from './pages';
import { QueryClientProvider } from '@tanstack/react-query';
import { queryClient } from '@apis/index';
import withUserId from '@hocs/withUserId';
import ReplayPage from '@pages/ReplayPage';

function App() {
function AppComponent() {
return (
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<Router>
<Router
future={{
v7_startTransition: true,
v7_relativeSplatPath: true
}}
>
<Routes>
<Route path="/" element={<MainPage />} />

<Route path="/live" element={<ClientPage />} />
<Route path="/live/:id" element={<ClientPage />} />

<Route path="/replay" element={<ReplayPage />} />
<Route path="/replay/:id" element={<ReplayPage />} />
<Route path="/host" element={<HostPage />} />
<Route path="/host/:id" element={<HostPage />} />
</Routes>
Expand All @@ -26,4 +32,6 @@ function App() {
);
}

const App = withUserId(AppComponent);

export default App;
17 changes: 17 additions & 0 deletions frontend/src/apis/fetchBroadcastStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { fetchInstance } from '.';

export type BroadcastStatusResponse = {
state: boolean;
};

export const fetchBroadcastStatus = async (sessionKey: string): Promise<BroadcastStatusResponse> => {
const response = await fetchInstance().get<BroadcastStatusResponse>('/host/state', {
params: {
sessionKey
}
});

return {
state: response.data.state
};
};
17 changes: 17 additions & 0 deletions frontend/src/apis/fetchLive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AxiosResponse } from 'axios';
import { fetchInstance } from '.';
import { ClientLive } from '@type/live';

type ClientLiveResponse = {
info: ClientLive;
};

export const fetchLive = async ({ liveId }: { liveId: string }): Promise<ClientLive> => {
const response: AxiosResponse<ClientLiveResponse> = await fetchInstance().get('/streams/live', {
params: {
liveId
}
});

return response.data.info;
};
13 changes: 13 additions & 0 deletions frontend/src/apis/fetchMainLive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AxiosResponse } from 'axios';
import { fetchInstance } from '.';
import { MainLive } from '@type/live';

type MainLiveResponse = {
info: MainLive[];
};

export const fetchMainLive = async (): Promise<MainLive[]> => {
const response: AxiosResponse<MainLiveResponse> = await fetchInstance().get('/streams/random');

return response.data.info;
};
9 changes: 9 additions & 0 deletions frontend/src/apis/fetchRecentLive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AxiosResponse } from 'axios';
import { fetchInstance } from '.';
import { RecentLiveResponse } from '@type/live';

export const fetchRecentLive = async (): Promise<RecentLiveResponse> => {
const response: AxiosResponse = await fetchInstance().get('/streams/latest');

return response.data;
};
9 changes: 9 additions & 0 deletions frontend/src/apis/fetchRecentReplay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AxiosResponse } from 'axios';
import { fetchInstance } from '.';
import { RecentReplayResponse } from '@type/replay';

export const fetchRecentReplay = async (): Promise<RecentReplayResponse> => {
const response: AxiosResponse = await fetchInstance().get('/replay/latest');

return response.data;
};
17 changes: 17 additions & 0 deletions frontend/src/apis/fetchReplay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AxiosResponse } from 'axios';
import { fetchInstance } from '.';
import { ReplayStream } from '@type/replay';

type ReplayStreamResponse = {
info: ReplayStream;
};

export const fetchReplay = async ({ videoId }: { videoId: string }): Promise<ReplayStream> => {
const response: AxiosResponse<ReplayStreamResponse> = await fetchInstance().get('/replay/video', {
params: {
videoId
}
});

return response.data.info;
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { AxiosResponse } from 'axios';
import { BASE_URL, fetchInstance } from '..';

type StreamKeyResponse = {
'stream-key': string;
'session-key': string;
};
import { fetchInstance } from '.';

type NanoId = string;

export type StreamKeyResponse = {
streamKey: string;
sessionKey: string;
};

export const fetchStreamKey = async (userId: NanoId): Promise<StreamKeyResponse> => {
const response: AxiosResponse<StreamKeyResponse> = await fetchInstance().post(`${BASE_URL}/host/key`, { userId });
const response: AxiosResponse<StreamKeyResponse> = await fetchInstance().post('/host/key', {
userId
});
return response.data;
};
8 changes: 6 additions & 2 deletions frontend/src/apis/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { QueryClient, DefaultOptions } from '@tanstack/react-query';
import axios from 'axios';

export const BASE_URL = 'http://liboo.kr';
export const BASE_URL = 'https://liboo.kr';
export const RTMP_PORT = '1935';
export const RTMP_HTTP_PORT = '8000';
export const API_PORT = '3000';

export const initFetchInstance = (baseURL: string) =>
axios.create({
Expand All @@ -12,7 +15,8 @@ export const initFetchInstance = (baseURL: string) =>
}
});

export const fetchInstance = () => initFetchInstance(BASE_URL);
export const fetchInstance = () => initFetchInstance(`${BASE_URL}:${API_PORT}`);
export const fetchRTMPInstance = () => initFetchInstance(`${BASE_URL}:${RTMP_HTTP_PORT}`);

const defaultOptions: DefaultOptions = {
queries: {
Expand Down
12 changes: 12 additions & 0 deletions frontend/src/apis/queries/client/useFetchLive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useQuery } from '@tanstack/react-query';

import { fetchLive } from '@apis/fetchLive';
import { ClientLive } from '@type/live';

export const useClientLive = ({ liveId }: { liveId: string }) => {
return useQuery<ClientLive, Error>({
queryKey: ['clientLive'],
queryFn: () => fetchLive({ liveId: liveId }),
refetchOnWindowFocus: false
});
};
15 changes: 15 additions & 0 deletions frontend/src/apis/queries/host/useBroadcastStatusPolling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useQuery } from '@tanstack/react-query';
import { fetchBroadcastStatus } from '@apis/fetchBroadcastStatus';

export const useBroadcastStatusPolling = (sessionKey: string, pollingInterVal = 10000) => {
return useQuery({
queryKey: ['broadcastState', sessionKey],
queryFn: () => fetchBroadcastStatus(sessionKey),
refetchInterval: pollingInterVal,
refetchIntervalInBackground: true,
refetchOnWindowFocus: true,
retry: 3,
initialData: { state: false },
select: (data) => data.state
});
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { fetchStreamKey } from '@apis/host/fetchStreamKey';
import { fetchStreamKey, StreamKeyResponse } from '@apis/fetchStreamKey';
import { useMutation, UseMutationResult } from '@tanstack/react-query';

type StreamKeyResponse = {
'stream-key': string;
'session-key': string;
};

type Params = {
onSuccess?: (data: StreamKeyResponse) => void;
onError?: (error: Error) => void;
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/apis/queries/host/useUpdateHost.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { updateHost } from '@apis/updateHost';
import { useMutation, UseMutationResult } from '@tanstack/react-query';
import { HostInfo } from '@type/hostInfo';

type Params = {
onSuccess?: (data: HostInfo) => void;
onError?: (error: Error) => void;
};

export default function useUpdateHost({ onSuccess, onError }: Params = {}): UseMutationResult<
HostInfo,
Error,
HostInfo
> {
return useMutation({
mutationFn: (hostInfo: HostInfo) => updateHost(hostInfo),
onSuccess,
onError
});
}
12 changes: 12 additions & 0 deletions frontend/src/apis/queries/main/useFetchMainLive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useSuspenseQuery } from '@tanstack/react-query';

import { fetchMainLive } from '@apis/fetchMainLive';
import { MainLive } from '@type/live';

export const useMainLive = () => {
return useSuspenseQuery<MainLive[], Error>({
queryKey: ['mainLive'],
queryFn: fetchMainLive,
refetchOnWindowFocus: false,
});
};
13 changes: 13 additions & 0 deletions frontend/src/apis/queries/main/useFetchRecentLive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useQuery } from '@tanstack/react-query';

import { fetchRecentLive } from '@apis/fetchRecentLive';
import { RecentLiveResponse } from '@type/live';

export const useRecentLive = () => {
return useQuery<RecentLiveResponse, Error>({
queryKey: ['recentLive'],
queryFn: fetchRecentLive,
refetchOnWindowFocus: false,
initialData: { info: [], appendInfo: [] }
});
};
13 changes: 13 additions & 0 deletions frontend/src/apis/queries/main/useFetchRecentReplay.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useQuery } from '@tanstack/react-query';

import { fetchRecentReplay } from '@apis/fetchRecentReplay';
import { RecentReplayResponse } from '@type/replay';

export const useRecentReplay = () => {
return useQuery<RecentReplayResponse, Error>({
queryKey: ['recentReplay'],
queryFn: fetchRecentReplay,
refetchOnWindowFocus: false,
initialData: { info: [], appendInfo: [] }
});
};
Loading

0 comments on commit 88aca02

Please sign in to comment.