Skip to content

Commit 1b3f9cd

Browse files
authored
Merge pull request #119 from GDGoCINHA/develop
Deploy(#102) Fix(#96, #116)/ refactored study, enhance special components and update SEO
2 parents 6b1d319 + 72a8aa4 commit 1b3f9cd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1933
-1033
lines changed

package-lock.json

Lines changed: 222 additions & 190 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
"gsap": "^3.12.7",
2525
"hangul-js": "^0.2.6",
2626
"lucide-react": "^0.507.0",
27-
"next": "15.0.2",
27+
"next": ">=15.2.3",
2828
"react": "^18.2.0",
2929
"react-dom": "^18.2.0",
30+
"react-error-boundary": "^6.0.0",
3031
"react-icons": "^5.4.0",
3132
"type-hangul": "^0.2.4"
3233
},

public/manifest.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"name": "GDGoC INHA University",
3-
"short_name": "GDGoC Inha Univ.",
2+
"name": "GDGoC INHA Univ.",
3+
"short_name": "GDGoC INHA",
44
"description": "Google Developer Group on Campus at Inha University",
55
"start_url": "/",
66
"display": "standalone",
@@ -34,7 +34,7 @@
3434
},
3535
{
3636
"src": "/icons/icon-144x144.png",
37-
"sizes": "144x144",
37+
"sizes": "144x70",
3838
"type": "image/png",
3939
"purpose": "any maskable"
4040
},
@@ -110,7 +110,7 @@
110110
"sizes": "1280x720",
111111
"type": "image/png",
112112
"platform": "wide",
113-
"label": "GDGoC INHA 홈페이지"
113+
"label": "GDGoC INHA Home"
114114
}
115115
]
116116
}

src/app/error.js

Lines changed: 93 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,118 @@
11
'use client';
22

3-
import React from 'react';
4-
import {Button} from "@nextui-org/react";
5-
import {useRouter} from "next/navigation";
3+
import { useState, useEffect } from 'react';
4+
import { Button } from "@nextui-org/react";
65
import Image from 'next/image';
6+
7+
// components
8+
import Forbidden from '@/app/forbidden';
9+
import Unauthorized from '@/app/unauthorized';
10+
11+
// resource
712
import gdgocIcon from "@public/src/images/GDGoC_icon.png";
813

9-
export default function Error({error, reset}) {
10-
const router = useRouter();
11-
const errorCode = error?.statusCode || error?.status || 'Internal Server';
14+
/**
15+
* @typedef {Object} ErrorProps
16+
* @property {Error} error - The error object
17+
* @property {() => void} reset - Function to reset the error state
18+
*/
19+
export default function Error({ error, reset = () => {} }) {
20+
const [countdown, setCountdown] = useState(5);
21+
const errorCode = error?.statusCode || error?.status || 500;
22+
const errorTitle = error?.title || 'Internal Server Error';
1223
const errorMessage = error?.message || 'Unknown Error has occurred';
1324

25+
useEffect(() => {
26+
if (process.env.NODE_ENV === 'development') {
27+
console.log(error || 'Unknown Error has occurred');
28+
}
29+
}, []);
30+
31+
useEffect(() => {
32+
if (countdown > 0) {
33+
const timer = setTimeout(() => setCountdown(countdown - 1), 1000);
34+
return () => clearTimeout(timer);
35+
}
36+
}, [countdown]);
37+
1438
const handleClick = () => {
1539
reset();
1640
window.location.reload();
1741
};
1842

43+
// Handle specific error codes
44+
if (errorCode === 401) {
45+
return <Unauthorized />;
46+
}
47+
48+
if (errorCode === 403) {
49+
return <Forbidden />;
50+
}
51+
1952
return (
20-
<div className="flex flex-col items-center justify-center min-h-screen relative">
21-
<div className="absolute inset-0 flex items-center justify-center opacity-35 pointer-events-none z-0">
22-
<Image
23-
src={gdgocIcon}
24-
alt="GDGoC Icon"
25-
width={500}
26-
height={500}
27-
/>
53+
<div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-gray-900 to-black relative overflow-hidden">
54+
{/* 아이콘 배경 */}
55+
<div className="absolute inset-0 flex items-center justify-center opacity-10 pointer-events-none z-0" aria-hidden="true">
56+
<div className="relative">
57+
<Image
58+
src={gdgocIcon}
59+
alt="GDGoC Icon"
60+
width={600}
61+
height={600}
62+
className="animate-pulse"
63+
priority
64+
/>
65+
</div>
2866
</div>
2967

30-
<div className="z-10">
31-
<div className="flex flex-col items-center justify-center">
32-
<h1 className="text-3xl font-bold text-white">{errorCode} Error</h1>
33-
<p className="mt-2 text-lg text-white">페이지 로드 중 에러가 발생하였습니다.</p>
34-
<p className="text-lg text-white">개발팀으로 연락 바랍니다!</p>
35-
{/* only at development env */}
68+
{/* 오류 박스 */}
69+
<div className="z-10 bg-gray-800/70 backdrop-blur-sm p-4 sm:p-8 rounded-xl shadow-2xl border border-red-500/20 max-w-[90%] sm:max-w-md w-full mx-4">
70+
<div className="flex flex-col items-center justify-center text-center">
71+
{/* 오류 아이콘 */}
72+
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-red-500/10 flex items-center justify-center mb-4 sm:mb-6" role="img" aria-label="Error icon">
73+
<svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8 sm:h-10 sm:w-10 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
74+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
75+
</svg>
76+
</div>
77+
78+
{/* 오류 내용 */}
79+
<h1 className="text-3xl sm:text-4xl font-bold text-white mb-2">
80+
<p className="text-red-500 text-2xl sm:text-3xl md:text-4xl lg:text-5xl">{errorCode}</p>
81+
<span className="block text-white text-base sm:text-lg md:text-xl lg:text-2xl">{errorTitle}</span>
82+
</h1>
83+
<div className="w-12 sm:w-16 h-1 bg-gradient-to-r from-red-500 to-red-400 rounded-full mb-3 sm:mb-4" aria-hidden="true"></div>
84+
85+
<div className="bg-red-500/10 py-3 px-6 rounded-lg border border-red-500/20">
86+
<p className="text-base sm:text-lg text-red-100">페이지 로드 중 에러가 발생하였습니다.</p>
87+
<p className="text-base sm:text-lg text-red-100">Tech팀으로 연락 바랍니다!</p>
88+
</div>
89+
90+
{/* 개발 환경에서만 표시 */}
3691
{process.env.NODE_ENV === 'development' && (
37-
<div className="mt-4 p-4 bg-[#1f1f1f] rounded-lg max-w-md">
38-
<p className="text-yellow-500 text-sm font-mono break-words">{errorMessage}</p>
92+
<div className="mt-2 p-3 sm:p-4 bg-red-500/5 rounded-lg border border-red-500/20 max-w-[90%] sm:max-w-md w-full overflow-auto">
93+
<p className="text-yellow-400 text-xs sm:text-sm font-mono break-words">{errorMessage}</p>
3994
</div>
4095
)}
96+
97+
{/* 버튼 */}
4198
<Button
4299
onPress={handleClick}
43-
className="mt-8 w-72 max-w-sm h-12 bg-red-500 text-white text-lg font-semibold rounded-lg"
100+
className="mt-6 sm:mt-8 w-full max-w-[280px] h-10 sm:h-12 bg-gradient-to-r from-red-500 to-red-400 hover:from-red-400 hover:to-red-500 text-white text-base sm:text-lg font-semibold rounded-lg transition-all duration-300 shadow-lg hover:shadow-red-500/30"
101+
aria-label={`다시 시도하기 ${countdown > 0 ? `(${countdown}초)` : ''}`}
44102
>
45-
다시 시도하기
103+
다시 시도하기 {countdown > 0 && `(${countdown}초)`}
46104
</Button>
105+
106+
{/* 작은 로고 */}
107+
<div className="mt-4 sm:mt-6">
108+
<Image
109+
src={gdgocIcon}
110+
alt="GDGoC Small Icon"
111+
width={32}
112+
height={32}
113+
className="opacity-50"
114+
/>
115+
</div>
47116
</div>
48117
</div>
49118
</div>

src/app/forbidden.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// this is experimental page for nextjs
2+
'use client';
3+
4+
import { useRouter } from "next/navigation";
5+
import { Button } from "@nextui-org/react";
6+
import Image from 'next/image';
7+
8+
// resource
9+
import gdgocIcon from "@public/src/images/GDGoC_icon.png";
10+
11+
export default function Forbidden() {
12+
const router = useRouter();
13+
14+
const handleClick = () => {
15+
const sameOrigin = document.referrer.startsWith(window.location.origin);
16+
if (sameOrigin) {
17+
router.back();
18+
} else {
19+
router.push("/");
20+
}
21+
};
22+
23+
return (
24+
<div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-b from-gray-900 to-black relative overflow-hidden">
25+
{/* 아이콘 배경 */}
26+
<div className="absolute inset-0 flex items-center justify-center opacity-10 pointer-events-none z-0" aria-hidden="true">
27+
<div className="relative">
28+
<Image
29+
src={gdgocIcon}
30+
alt="GDGoC Icon"
31+
width={600}
32+
height={600}
33+
className="animate-pulse"
34+
priority
35+
/>
36+
</div>
37+
</div>
38+
39+
{/* 403 에러 박스 */}
40+
<div className="z-10 bg-gray-800/70 backdrop-blur-sm p-4 sm:p-8 rounded-xl shadow-2xl border border-red-500/20 max-w-[90%] sm:max-w-md w-full mx-4">
41+
<div className="flex flex-col items-center justify-center text-center">
42+
{/* 403 아이콘 */}
43+
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-red-500/10 flex items-center justify-center mb-4 sm:mb-6" role="img" aria-label="403 icon">
44+
<svg xmlns="http://www.w3.org/2000/svg" className="h-8 w-8 sm:h-10 sm:w-10 text-red-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
45+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
46+
</svg>
47+
</div>
48+
49+
{/* 403 내용 */}
50+
<h1 className="text-3xl sm:text-4xl font-bold text-white mb-2">
51+
<span className="text-red-500">403</span> Forbidden
52+
</h1>
53+
<div className="w-12 sm:w-16 h-1 bg-gradient-to-r from-red-500 to-red-400 rounded-full mb-3 sm:mb-4" aria-hidden="true"></div>
54+
55+
<div className="bg-red-500/10 py-3 px-6 rounded-lg border border-red-500/20">
56+
<p className="text-base sm:text-lg text-red-100">접근 권한이 없는 페이지입니다.</p>
57+
<p className="text-base sm:text-lg text-red-100">이전 페이지로 이동해주세요.</p>
58+
</div>
59+
60+
{/* 버튼 */}
61+
<Button
62+
onPress={handleClick}
63+
className="mt-6 sm:mt-8 w-full max-w-[280px] h-10 sm:h-12 bg-gradient-to-r from-red-500 to-red-400 hover:from-red-400 hover:to-red-500 text-white text-base sm:text-lg font-semibold rounded-lg transition-all duration-300 shadow-lg hover:shadow-red-500/30"
64+
aria-label="이전 페이지로 이동"
65+
>
66+
이전 페이지로 이동
67+
</Button>
68+
69+
{/* 작은 로고 */}
70+
<div className="mt-4 sm:mt-6">
71+
<Image
72+
src={gdgocIcon}
73+
alt="GDGoC Small Icon"
74+
width={32}
75+
height={32}
76+
className="opacity-50"
77+
/>
78+
</div>
79+
</div>
80+
</div>
81+
</div>
82+
);
83+
}

0 commit comments

Comments
 (0)