Skip to content

Commit

Permalink
[feat] 메인화면, 방송화면에서 닉네임을 받아오는 기능 구현 (#150)
Browse files Browse the repository at this point in the history
* feat : 메인화면, 방송화면에서 닉네임 받아오도록 하기

* feat : 30초마다 스트리머 정보 갱신하는 기능 구현

* fix : front docker run할때 env파일 부여

* fix : ID 및 닉네임 수정 오류 수정

---------

Co-authored-by: ChoiSangwon <[email protected]>
  • Loading branch information
Novrule and ChoiSangwon authored Dec 6, 2023
1 parent 9263022 commit b87e687
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 206 deletions.
94 changes: 47 additions & 47 deletions .github/workflows/deploy-front.yml
Original file line number Diff line number Diff line change
@@ -1,56 +1,56 @@
name: auto deploy front

on:
push:
branches:
- dev
push:
branches:
- dev

jobs:
docker_push_front:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
docker_push_front:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3

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

- name: Login to NCP Container Registry
uses: docker/login-action@v2
with:
registry: ${{ secrets.NCP_CONTAINER_REGISTRY }}
username: ${{ secrets.NCP_ACCESS_KEY }}
password: ${{ secrets.NCP_SECRET_KEY }}
- name: Login to NCP Container Registry
uses: docker/login-action@v2
with:
registry: ${{ secrets.NCP_CONTAINER_REGISTRY }}
username: ${{ secrets.NCP_ACCESS_KEY }}
password: ${{ secrets.NCP_SECRET_KEY }}

- name: Build and Push Docker Image
uses: docker/build-push-action@v3
with:
context: ./client
file: ./client/Dockerfile
push: true
tags: ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
cache-from: type=registry,ref=${{ secrets.NCP_CONTAINER_REGISTRY }}/front
cache-to: type=inline
- name: Build and Push Docker Image
uses: docker/build-push-action@v3
with:
context: ./client
file: ./client/Dockerfile
push: true
tags: ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
cache-from: type=registry,ref=${{ secrets.NCP_CONTAINER_REGISTRY }}/front
cache-to: type=inline

docker_pull_front:
name: Connect server ssh and pull frontend from container registry
needs: docker_push_front
runs-on: ubuntu-latest
steps:
- name: connect ssh
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.FRONT_HOST }}
username: ${{ secrets.FRONT_USERNAME }}
password: ${{ secrets.FRONT_PASSWORD }}
port: ${{ secrets.FRONT_PORT }}
script: |
docker pull ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
docker run -d -p 80:80 -p 443:443 --name front ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
docker image prune -f
docker cp /etc/letsencrypt/archive/gbs-live.site/fullchain1.pem front:/
docker cp /etc/letsencrypt/archive/gbs-live.site/privkey1.pem front:/
docker cp default.conf front:/etc/nginx/conf.d/
docker exec front nginx -s reload
docker_pull_front:
name: Connect server ssh and pull frontend from container registry
needs: docker_push_front
runs-on: ubuntu-latest
steps:
- name: connect ssh
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.FRONT_HOST }}
username: ${{ secrets.FRONT_USERNAME }}
password: ${{ secrets.FRONT_PASSWORD }}
port: ${{ secrets.FRONT_PORT }}
script: |
docker pull ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
docker run -d -p 80:80 -p 443:443 --name front --env-file ${{ secrets.ENV_PATH }} ${{ secrets.NCP_CONTAINER_REGISTRY }}/front
docker image prune -f
docker cp /etc/letsencrypt/archive/gbs-live.site/fullchain1.pem front:/
docker cp /etc/letsencrypt/archive/gbs-live.site/privkey1.pem front:/
docker cp default.conf front:/etc/nginx/conf.d/
docker exec front nginx -s reload
2 changes: 1 addition & 1 deletion client/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ FROM --platform=linux/amd64 node:lts-alpine as build-stage
WORKDIR /app

# 의존성 파일 복사 및 설치
COPY package.json yarn.lock .env ./
COPY package.json yarn.lock ./
RUN yarn install && yarn global add typescript

# 소스 코드 복사
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Broadcast/Broadcast.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const Broadcast = styled.div<BroadcastProps>`
height: 15rem;
`

export const Thumbnail = styled.div`
export const Thumbnail = styled.img`
border: 0.0625rem solid #000000;
position: absolute;
top: 1.875rem;
Expand Down
8 changes: 5 additions & 3 deletions client/src/components/Broadcast/Broadcast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@ import * as styles from './Broadcast.styles'
import { themeState } from '@/states/theme'

interface BroadcastProps {
thumbnail: string
title: string
nickname: string
viewer: string
viewer: number
index: number
}

const Broadcast = ({ title, nickname, viewer, index }: BroadcastProps) => {
const Broadcast = ({ thumbnail, title, nickname, viewer, index }: BroadcastProps) => {
const theme = useRecoilValue(themeState)

return (
<styles.Broadcast index={index} currentTheme={theme}>
<styles.Thumbnail></styles.Thumbnail>
<styles.Thumbnail src={thumbnail} />
<styles.Title>{title}</styles.Title>
<styles.Nickname>{nickname}</styles.Nickname>
<styles.Viewer>시청자 {viewer}</styles.Viewer>
Expand Down
38 changes: 18 additions & 20 deletions client/src/components/Modal/LoginModal/LoginModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import useApi from '@/hooks/useApi'
import * as styles from './LoginModal.styles'
import { ThemeFlag } from '@/types/theme'

Expand All @@ -8,29 +7,28 @@ interface LoginModalProps {
}

const LoginModal = ({ onCancle, currentTheme }: LoginModalProps) => {
const [response, fetchApi] = useApi<{ userId: string; nickname: string }>()

const onLoginImage = () => {
const popup = window.open(`${import.meta.env.VITE_API_URL}` + '/oauth/login/naver', '_blank', 'menubar=no, toolbar=no, width=500, height=600')

const popupEvent = async () => {
if (popup !== null && popup.closed === true) {
try {
await fetchApi('GET', '/users/me/', undefined, { credentials: 'include' })

if (response.data) {
const { userId, nickname } = response.data

localStorage.setItem('user', JSON.stringify({ id: userId, nickname: nickname }))
const popupEvent = () => {
if (popup !== null && popup.closed == true) {
fetch(`${import.meta.env.VITE_API_URL}` + '/users/me/', { method: 'GET', credentials: 'include' })
.then((res) => {
if (res.ok === true) {
return res.json()
} else {
throw new Error('Login Failed')
}
})
.then((res) => {
const userId = res.userId
const userNickname = res.nickname

localStorage.setItem('user', JSON.stringify({ id: userId, nickname: userNickname }))
window.location.reload()
} else {
throw new Error('Login Failed')
}
} catch (error) {
console.error(response.error || error)
} finally {
window.removeEventListener('focus', popupEvent)
}
})
.catch((err) => console.error(err))
.finally(() => window.removeEventListener('focus', popupEvent))
}
}

Expand Down
103 changes: 68 additions & 35 deletions client/src/components/Modal/SettingModal/SettingModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,25 @@ import * as styles from './SettingModal.styles'
import { ThemeFlag } from '@/types/theme'
import { themeState } from '@/states/theme'
import { userState } from '@/states/user'
import useApi from '@/hooks/useApi'

interface SettingModalProps {
onConfirm: () => void
}

const SettingModal = ({ onConfirm }: SettingModalProps) => {
const [currentTheme, setTheme] = useRecoilState(themeState)
const isDarkMode = currentTheme === ThemeFlag.dark
const [user, setUser] = useRecoilState(userState)
const [id, setId] = useState<string>(user.id)
const [nickname, setNickname] = useState<string>(user.nickname)
const [streamKey, setStreamKey] = useState<string>('')
const [response, fetchApi] = useApi()
const isDarkMode = currentTheme === ThemeFlag.dark

const onToggleContainer = () => {
setTheme(isDarkMode ? ThemeFlag.light : ThemeFlag.dark)
localStorage.setItem('theme', `${currentTheme}`)
}

const onIdInputButton = async () => {
const onIdInputButton = () => {
if (id.trim() === '') {
alert('올바른 ID를 입력해주세요.')
setId(user.id)
Expand All @@ -35,19 +33,34 @@ const SettingModal = ({ onConfirm }: SettingModalProps) => {

return
}
await fetchApi('PATCH', '/users/', { nickname: user.nickname, userId: id.trim() })

if (response.data) {
const { userId, nickname } = response.data
alert('ID가 저장되었습니다.')
setUser({ id: userId, nickname: nickname })
localStorage.setItem('user', JSON.stringify({ id: userId, nickname: nickname }))
} else {
console.log(response.error)
}

fetch(`${import.meta.env.VITE_API_URL}` + '/users', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ nickname: user.nickname, userId: id.trim() }),
credentials: 'include',
})
.then((res) => {
if (res.ok === true) {
return res.json()
} else {
throw new Error('ID Save Failed')
}
})
.then((res) => {
const userId = res.userId
const userNickname = res.nickname

alert('ID가 저장되었습니다.')
setUser({ id: userId, nickname: userNickname })
localStorage.setItem('user', JSON.stringify({ id: userId, nickname: userNickname }))
})
.catch((err) => console.error(err))
}

const onNicknameInputButton = async () => {
const onNicknameInputButton = () => {
if (nickname.trim() === '') {
alert('올바른 닉네임을 입력해주세요.')
setNickname(user.nickname)
Expand All @@ -58,32 +71,52 @@ const SettingModal = ({ onConfirm }: SettingModalProps) => {

return
}
await fetchApi('PATCH', '/users/', { nickname: nickname.trim(), userId: user.id })

if (response.data) {
const { userId, nickname } = response.data
alert('닉네임이 저장되었습니다.')
setUser({ id: userId, nickname: nickname })
localStorage.setItem('user', JSON.stringify({ id: userId, nickname: nickname }))
} else {
console.log(response.error)
}
}

const onKeyInputButton = async () => {
await fetchApi('GET', '/stream-keys/me/')
fetch(`${import.meta.env.VITE_API_URL}` + '/users', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ nickname: nickname.trim(), userId: user.id }),
credentials: 'include',
})
.then((res) => {
if (res.ok === true) {
return res.json()
} else {
throw new Error('Nickname Save Failed')
}
})
.then((res) => {
const userId = res.userId
const userNickname = res.nickname

if (response.data) {
const { streamKey } = response.data
setStreamKey(streamKey)
navigator.clipboard.writeText(streamKey).then(() => {
alert('방송 비밀 키가 클립보드에 복사되었습니다.')
alert('닉네임이 저장되었습니다.')
setUser({ id: userId, nickname: userNickname })
localStorage.setItem('user', JSON.stringify({ id: userId, nickname: userNickname }))
})
}
.catch((err) => console.error(err))
}

const onKeyInputButton = () => {
navigator.clipboard.writeText(streamKey).then(() => {
alert('방송 비밀 키가 클립보드에 복사되었습니다.')
})
}

useEffect(() => {
onKeyInputButton()
fetch(`${import.meta.env.VITE_API_URL}` + '/stream-keys/me', { method: 'GET', credentials: 'include' })
.then((res) => {
if (res.ok === true) {
return res.json()
} else {
throw new Error('Get Stream Keys Failed')
}
})
.then((res) => {
setStreamKey(res.streamKey)
})
.catch((err) => console.error(err))
}, [])

return (
Expand Down
Loading

0 comments on commit b87e687

Please sign in to comment.