Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e6eda95
Fix: 정적배포를 위한 설정 업데이트 및 불필요한 파일 비활성화
pwc2002 Aug 27, 2025
27bc7f7
Feat: 정적배포용 api client 구현
pwc2002 Aug 28, 2025
9b63c84
Merge pull request #149 from GDGoCINHA/Fix/render
pwc2002 Aug 28, 2025
7ec8f0b
Fix: MenuHeader onPress로 변경하여 이벤트 핸들링 수정
ThinkMuk Aug 29, 2025
08f6f36
Refactor: Admin 페이지 컴포넌트 구조 개선 및 불필요한 코드 제거 #6
ThinkMuk Aug 29, 2025
9b53775
Refactor: accessToken 갱신 및 로그아웃 함수useCallback으로 최적화 #4
ThinkMuk Aug 30, 2025
009095c
Refactor: Admin 페이지에서 API 호출 및 데이터 처리 로직 개선, 검색 기능 활성화 #6
ThinkMuk Aug 30, 2025
6c91ae1
Refactor: UserDetailsModal 사용자 정보 표시 로직 개선 및 변경된 응답 스키마 반영 #6
ThinkMuk Aug 30, 2025
d1d1e81
Feat: Admin 회비 지불 여부 토글 기능 추가 #6
ThinkMuk Aug 30, 2025
f375fc4
Fix:deploy 세팅 수정
pwc2002 Aug 30, 2025
90043ea
Merge pull request #150 from GDGoCINHA/Fix/cicd재생성
pwc2002 Aug 30, 2025
57d2ff9
Fix: webpack 설정 추가 및 불필요한 export 스크립트 제거
pwc2002 Aug 30, 2025
a6dd80d
Merge pull request #152 from GDGoCINHA/Fix/cicd재생성
pwc2002 Aug 30, 2025
cc45788
Fix: deploy.yml에서 NODE_ENV 환경 변수 제거
pwc2002 Aug 30, 2025
1ed5a7f
Merge pull request #153 from GDGoCINHA/Fix/cicd재생성
pwc2002 Aug 30, 2025
ce02d83
Feat: 로그인 테스트 페이지에 cicd 배포 테스트 메시지 추가
pwc2002 Aug 30, 2025
8aaeebc
Merge pull request #154 from GDGoCINHA/Fix/cicd재생성
pwc2002 Aug 30, 2025
3b743f9
Merge pull request #151 from GDGoCINHA/Feat(#6)/admin
pwc2002 Aug 30, 2025
6efbf1f
Feat: 회원가입 및 로그인 페이지 개선, 이메일 중복 체크 기능 추가
pwc2002 Aug 30, 2025
233ff7f
Fix: HeroSection에서 '2025-1 Recruitment'를 '2025-2 Recruitment'로 수정
pwc2002 Aug 30, 2025
30852fa
Fix: Admin 페이지에서 총 가입자 수 표시 방식 수정
pwc2002 Aug 30, 2025
a8982f9
Fix: 회원가입 페이지에서 중복 체크 API 경로 수정 및 상태 처리 개선
pwc2002 Aug 31, 2025
2167783
Fix: 관리자 모달창 활성화 중 결제 토글버튼 오류 개선 #6
ThinkMuk Sep 1, 2025
03184f2
Fix: 관리자 총 가입자 수 표시 텍스트 수정 #6
ThinkMuk Sep 1, 2025
75d9e3a
Chore: yarn.lock 패키지 업데이트
ThinkMuk Sep 1, 2025
c29785b
Feat: 관리자 입금 상태 수정 시 확인 모달 추가 #6
ThinkMuk Sep 1, 2025
2305e14
Merge pull request #155 from GDGoCINHA/Feat(#6)/admin
ThinkMuk Sep 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 55 additions & 48 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,64 +1,71 @@
name: Build Docker and Upload to S3
name: DEV CI
permissions:
contents: read

on:
push:
branches:
- master
branches: [ develop ]
tags: [ 'development-**' ]
workflow_dispatch:

concurrency:
group: dev-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-upload:
deploy:
runs-on: ubuntu-latest
env:
NEXT_PUBLIC_BASE_API_URL: ${{ secrets.NEXT_PUBLIC_BASE_API_URL }}
NEXT_PUBLIC_GOOGLE_REDIRECT_CLIENT_ID: ${{ secrets.NEXT_PUBLIC_GOOGLE_REDIRECT_CLIENT_ID }}
NEXT_PUBLIC_GOOGLE_REDIRECT_URI: ${{ secrets.NEXT_PUBLIC_GOOGLE_REDIRECT_URI }}

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

- name: Create .env file
run: |
echo "DOCKER_HUB_USERNAME=${{ secrets.DOCKER_HUB_USERNAME }}" > .env
echo "NEXT_PUBLIC_BASE_API_URL=${{ secrets.NEXT_PUBLIC_BASE_API_URL }}" >> .env
echo "NEXT_PUBLIC_GOOGLE_REDIRECT_CLIENT_ID=${{secrets.NEXT_PUBLIC_GOOGLE_REDIRECT_CLIENT_ID}}" >> .env
echo "NEXT_PUBLIC_GOOGLE_REDIRECT_URI=${{secrets.NEXT_PUBLIC_GOOGLE_REDIRECT_URI}}" >> .env
- name: Checkout source code
uses: actions/checkout@v4

- name: Login to DockerHub (Optional)
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Use Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'yarn' # yarn.lock 기반 자동 캐시

- name: Build and Push Docker Image
run: |
docker build -t ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-fe-app:latest .
docker run --rm ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-fe-app:latest ls -la /app
docker push ${{ secrets.DOCKER_HUB_USERNAME }}/gdgoc-fe-app:latest
- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Create Deployment Package
run: |
cp scripts/deploy.sh ./deploy.sh
zip -r deploy.zip .env docker-compose.yml deploy.sh appspec.yml \
Dockerfile package.json package-lock.json next.config.ts \
pages public .next
- name: Build
run: yarn build

- name: Configure AWS credentials
run: |
aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws configure set region ${{ secrets.AWS_REGION }}
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Upload Deployment Package to S3
run: |
aws s3 cp deploy.zip s3://${{ secrets.AWS_S3_BUCKET }}/main-deploy.zip
# (선택) 캐시 헤더 전략: 해시된 자산은 장기 캐시, HTML은 no-cache
# 프로젝트에 맞게 include/exclude 패턴 조정
- name: Upload static assets (long cache)
run: |
aws s3 cp ./out s3://${{ secrets.AWS_S3_BUCKET }} \
--recursive \
--exclude "*" \
--include "_next/**" --include "static/**" --include "assets/**" \
--cache-control "public, max-age=31536000, immutable" \
--metadata-directive REPLACE
- name: Upload html (no cache)
run: |
aws s3 cp ./out s3://${{ secrets.AWS_S3_BUCKET }} \
--recursive \
--exclude "_next/*" --exclude "static/*" --exclude "assets/*" \
--cache-control "no-cache" \
--metadata-directive REPLACE
# (단순화 원하면 기존 sync 한 줄 유지 가능)
# - name: Deploy to S3
# run: aws s3 sync ./out s3://${{ secrets.AWS_S3_BUCKET }} --delete

- name: Trigger CodeDeploy (CLI)
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ap-northeast-2
run: |
aws deploy create-deployment \
--application-name ${{ secrets.AWS_CODEDEPLOY_APP }} \
--deployment-group-name ${{ secrets.AWS_CODEDEPLOY_GROUP }} \
--s3-location bucket=${{ secrets.S3_BUCKET }},bundleType=zip,key=main-deploy.zip \
--file-exists-behavior OVERWRITE
- name: Invalidate CloudFront Cache
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.AWS_DISTRIBUTION_ID }} \
--paths "/*"
10 changes: 10 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import type { NextConfig } from 'next';
import path from 'path';

const nextConfig: NextConfig = {
images: {
unoptimized: true,
},
trailingSlash: true,
output: 'export',
webpack: (config) => {
config.resolve.alias = {
...(config.resolve.alias || {}),
'@': path.resolve(__dirname, 'src'),
'@public': path.resolve(__dirname, 'public'),
};
return config;
},
};

export default nextConfig;
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"export": "next export"
"lint": "next lint"
},
"dependencies": {
"@heroicons/react": "^2.2.0",
Expand Down
16 changes: 16 additions & 0 deletions src/app/_auth/signin/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//import { Suspense } from "react";
import Header2 from '@/components/ui/common/Header2';

export const metadata = {
title: "SignIn",
description: "SignIn to your account",
};

export default function SignInLayout({ children }) {
return (
<div className='min-h-screen flex flex-col overflow-hidden relative'>
<Header2 />
{children}
</div>
);
}
146 changes: 146 additions & 0 deletions src/app/_auth/signin/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
'use client';

import { useState } from 'react';
import { useRouter } from 'next/navigation';
import Image from 'next/image';

import Header2 from '@/components/ui/common/Header2';
import Loader from '@/components/ui/common/Loader';

import AuthLogin from '@/components/auth/screen/AuthLogin';
import AuthFindId from '@/components/auth/screen/AuthFindId';
import AuthResetPassword from '@/components/auth/screen/AuthResetPassword';
import AuthResetRequest from '@/components/auth/screen/AuthResetRequest';

import { GoogleLogin } from '@/services/auth/signin/google/GoogleLogin';
import { login } from '@/services/auth/signin/custom/CustomAuthApi';

import { useAuth } from '@/hooks/useAuth';

import loginBg from '@public/images/bgimg.png';

export default function Page() {
const router = useRouter();
const { setAccessToken } = useAuth();
const { handleGoogleLogin } = GoogleLogin();

const [password, setPassword] = useState('');
const [errors, setErrors] = useState([]);
const [isRendering, setIsRendering] = useState(0);
const [loading, setLoading] = useState(false);

const handleBackToLogin = () => setIsRendering(0);
const handleFindIdClick = () => setIsRendering(1);
const handleResetPasswordClick = () => setIsRendering(2);
const handleBackToResetRequest = () => setIsRendering(2);
const handleResetPasswordNext = () => setIsRendering(3);

const validatePassword = (password) => {
const newErrors = [];
if (password.length <= 0) {
newErrors.push('비밀번호를 입력해주세요.');
}
return newErrors;
};

const onSubmit = async (e) => {
e.preventDefault();

const formData = Object.fromEntries(new FormData(e.currentTarget));
const passwordErrors = validatePassword(password);

if (passwordErrors.length > 0) {
setErrors(passwordErrors);
} else {
setErrors([]);

try {
const { email, password } = formData;
setLoading(true);
const res = await login(email, password);
const { exists, access_token } = res.data.data;

if (!exists) {
alert('아이디 혹은 비밀번호가 올바르지 않습니다.');
setLoading(false);
return;
}

setAccessToken(access_token);
router.push('/main');
} catch (error) {
console.error('로그인 실패:', error);
alert('로그인 중 오류가 발생했습니다.');
setLoading(false);
}
}
};

return (
<>
<Loader isLoading={loading} />
<Image src={loginBg} alt='loginBg' fill className='absolute top-0 left-0 -z-10 object-cover opacity-70 blur-sm' />
<div className='flex justify-center items-center flex-1 relative'>
{/* 로그인 화면 */}
<div
key='screen1'
className={`absolute w-full transition-all duration-500 ease-in-out transform ${
isRendering === 0 ? 'translate-x-0 opacity-100' : '-translate-x-full opacity-0'
} flex justify-center items-center`}
>
<AuthLogin
router={router}
onSubmit={onSubmit}
errors={errors}
password={password}
setPassword={setPassword}
setErrors={setErrors}
handleGoogleLogin={handleGoogleLogin}
handleFindIdClick={handleFindIdClick}
handleResetPasswordClick={handleResetPasswordClick}
/>
</div>

{/* 아이디 찾기 화면 */}
<div
key='screen2'
className={`absolute w-full transition-all duration-500 ease-in-out transform ${
isRendering === 1 ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'
} flex justify-center items-center mt-[-30px]`}
>
<AuthFindId handleBackToLogin={handleBackToLogin} />
</div>

{/* 비밀번호 재설정 화면 1 */}
<div
key='screen3'
className={`absolute w-full transition-all duration-500 ease-in-out transform ${
isRendering === 2
? 'translate-x-0 opacity-100'
: `${isRendering === 3 ? '-translate-x-full' : 'translate-x-full'} opacity-0`
} flex justify-center items-center`}
>
<AuthResetRequest
handleNextStep={handleResetPasswordNext}
handleBackToLogin={handleBackToLogin}
setLoading={setLoading}
/>
</div>

{/* 비밀번호 재설정 화면 2 */}
<div
key='screen4'
className={`absolute w-full transition-all duration-500 ease-in-out transform ${
isRendering === 3 ? 'translate-x-0 opacity-100' : 'translate-x-full opacity-0'
} flex justify-center items-center`}
>
<AuthResetPassword
handleBackToLogin={handleBackToLogin}
handleBackToResetRequest={handleBackToResetRequest}
setLoading={setLoading}
/>
</div>
</div>
</>
);
}
16 changes: 16 additions & 0 deletions src/app/_auth/signup/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//import { Suspense } from "react";
import Header from "@/components/ui/common/Header";

export const metadata = {
title: "SignUp",
description: "SignUp to your account",
};

export default function SignUpLayout({ children }) {
return (
<>
<Header />
{children}
</>
);
}
Loading