Skip to content

Commit

Permalink
Merge branch 'dev' into WV-46-fix-mixed-content-error
Browse files Browse the repository at this point in the history
  • Loading branch information
Jinviz authored Jan 16, 2025
2 parents 52b6138 + 7ea3fa1 commit 759c618
Show file tree
Hide file tree
Showing 23 changed files with 478 additions and 72 deletions.
18 changes: 18 additions & 0 deletions api/news/apis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const BASE_URL = process.env.NEXT_PUBLIC_API_KEY;

// news-detail
export const getNewsDetail = async (
artcSeq: string
): Promise<ArticleContentsResponse["data"]> => {
const queryparam = artcSeq ? `newsdetail?artcSeq=${artcSeq}` : "";

const url = `${BASE_URL}/article/${queryparam}`;
const res = await fetch(url);

if (!res.ok) {
throw new Error("Failed to fetch news detail");
}

const response: ArticleContentsResponse = await res.json();
return response.data;
};
5 changes: 5 additions & 0 deletions api/news/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type ArticleContentsResponse = {
data: {
article: ArticleContentsType;
};
};
23 changes: 22 additions & 1 deletion api/player/apis.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { CoachDetailResponse, CoachResponse, PitcherResponse } from "./types";
import {
CoachDetailResponse,
CoachResponse,
PitcherDetailResponse,
PitcherResponse,
} from "./types";

// player - 코치 리스트
export const getCoachList = async (): Promise<CoachInfo[]> => {
Expand Down Expand Up @@ -40,3 +45,19 @@ export const getCoachDetail = async (
const data = await response.json();
return data.data;
};

// player - 투수 디테일
export const getPitcherDetail = async (
pcode: string
): Promise<PitcherDetailResponse["data"]> => {
const queryparam = pcode ? `pitcherdetail?pcode=${pcode}` : "";
const url = `${BASE_URL}/player/${queryparam}`;
const response = await fetch(url, { method: "GET" });

if (!response.ok) {
throw new Error("투수의 디테일한 정보를 가져올수 없음");
}

const data = await response.json();
return data.data;
};
11 changes: 11 additions & 0 deletions api/player/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,14 @@ export type CoachDetailResponse = {
};
};
};

export type PitcherDetailResponse = {
data: {
gameplayer: PitcherPersonalInfo;
recentgamerecordlist: PitcherGameRecord[];
recentgamerecordlistfutures: PitcherGameRecord[];
seasonsummary: PitcherSeasonSummary;
seasonsummaryfutures: PitcherSeasonSummary;
yearrecordlist: PitcherYearRecord[];
};
};
7 changes: 7 additions & 0 deletions app/(menu)/media/news/[artcSeq]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { getNewsDetail } from "@/api/news/apis";
import { NewsDetail } from "@/components/media/news-detail";

export default async function page() {
const { article } = await getNewsDetail("190048"); //임시
return <NewsDetail data={article} />;
}
2 changes: 1 addition & 1 deletion app/(menu)/player/coach/[pcode]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getCoachDetail } from "@/api/player/apis";
import { CoachDetail } from "@/components/player/coach-detail";
import { CoachDetail } from "@/components/player/coach/coach-detail";

export default async function Page({
params,
Expand Down
2 changes: 1 addition & 1 deletion app/(menu)/player/coach/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getCoachList } from "@/api/player/apis";
import { CoachList } from "@/components/player/coach-list";
import { CoachList } from "@/components/player/coach/coach-list";
export const dynamic = "force-dynamic";
export default async function Page() {
const coachList = await getCoachList();
Expand Down
16 changes: 13 additions & 3 deletions app/(menu)/player/pitcher/[pcode]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
export default async function Page() {
import { getPitcherDetail } from "@/api/player/apis";
import { PitcherDetail } from "@/components/player/pitcher/pitcher-detail";

export default async function Page({
params,
}: {
params: {
pcode: string;
};
}) {
const { pcode } = params;
const data = await getPitcherDetail(pcode);
return (
<>
<div>투수 디테일 페이지</div>
{/* <CoachDetail /> */}
<PitcherDetail data={data} />
</>
);
}
2 changes: 1 addition & 1 deletion app/(menu)/player/pitcher/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { getPitcherList } from "@/api/player/apis";
import PitcherList from "@/components/player/pitcher-list";
import PitcherList from "@/components/player/pitcher/pitcher-list";
export const dynamic = "force-dynamic";
export default async function page() {
const pitcherList = await getPitcherList();
Expand Down
5 changes: 0 additions & 5 deletions app/(menu)/wizpark/iksan/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { BusRouteInfo } from "@/components/wizpark/iksan/bus-route-info";
import { IKSAN_IMAGES, IKSAN_LOCATION } from "@/constants/stadium";
import { Bus, ExternalLink, Images, Map, MapPin } from "lucide-react";
import Link from "next/link";
import Script from "next/script";

export default function page() {
return (
Expand All @@ -32,10 +31,6 @@ export default function page() {
</div>
</CardContent>
</Card>
<Script
strategy="beforeInteractive"
src={`https://dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_API_KEY}&libraries=services&autoload=false`}
/>
<CardHeader>
<CardTitle className="flex items-center">
<Map className="mr-2" />
Expand Down
5 changes: 0 additions & 5 deletions app/(menu)/wizpark/location/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,13 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui";
import KakaoMap from "@/components/common/Map";
import { Bus, ExternalLink, Map, MapPin, MoveRight, Train } from "lucide-react";
import Link from "next/link";
import Script from "next/script";
import { SUWON_LOCATION } from "@/constants/stadium";

export default function page() {


return (
<div>
<Script
strategy="beforeInteractive"
src={`https://dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_API_KEY}&libraries=services&autoload=false`}
/>
<CardHeader>
<CardTitle className="flex items-center">
<Map className="mr-2" />
Expand Down
4 changes: 4 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Header from "@/components/layout/header";
import Footer from "@/components/layout/footer";
import { Noto_Sans_KR } from "next/font/google";
import QueryProviders from "@/providers/query-provider";
import Script from "next/script";

const notoSansKr = Noto_Sans_KR({
subsets: ["latin"],
Expand All @@ -26,6 +27,9 @@ export default function RootLayout({
return (
<html lang="en">
<body className={notoSansKr.className}>
<Script
strategy="afterInteractive"
src={`https://dapi.kakao.com/v2/maps/sdk.js?appkey=${process.env.NEXT_PUBLIC_KAKAO_API_KEY}&libraries=services&autoload=false`} />
<div className="flex flex-col min-h-screen">
<Header />
<main className="flex-1">
Expand Down
62 changes: 62 additions & 0 deletions components/media/news-detail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { formatDate } from "date-fns";
import { CalendarDays, Eye } from "lucide-react";

export const NewsDetail = ({ data }: ArticleContentsProps) => {
const formatContent = (htmlContent: string) => {
const paragraphs = htmlContent
.split(/<\/?p[^>]*>/)
.filter((p) => p.trim().length > 0);

const formattedParagraphs = paragraphs.map((p) => {
if (p.includes("<img")) {
return `<p style="text-align: center">${p}</p>`;
}

const textContent = p.replace(/<[^>]*>/g, "").trim();
if (textContent) {
// 마침표와 느낌표를 기준으로 문장 나누기
const sentences = textContent
.split(/[.!]/) // 정규식으로 .과 ! 모두를 구분자로 사용
.filter((s) => s.trim().length > 0)
.map((s) => {
const originalEnding = textContent.charAt(
textContent.indexOf(s) + s.length
);
// 원래 문장의 마지막 부호(. 또는 !)를 유지
return `<p>${s.trim()}${originalEnding}</p>`;
})
.join("\n");
return sentences;
}
return "";
});

return formattedParagraphs.join("\n");
};

return (
<div className="max-w-4xl mx-auto p-4">
<div className="flex justify-between items-center">
<h1 className="text-2xl font-bold mb-6 bg-SYSTEM-main/30">
{data.artcTitle}
</h1>
<div className="flex items-center gap-1 h-fit">
<CalendarDays className="text-ELSE-7374 w-6 h-6" />
<div className="text-ELSE-7374 ">
{formatDate(data.regDttm, "yyyy.MM.dd")}
</div>
</div>
</div>
<div
className="space-y-2"
dangerouslySetInnerHTML={{
__html: formatContent(data.artcContents),
}}
/>
<div className="flex gap-1 pt-1">
<Eye className="text-ELSE-7374 w-6 h-6" />
<div className="text-ELSE-7374"> 조회수 : {data.viewCnt}</div>
</div>
</div>
);
};
21 changes: 21 additions & 0 deletions components/media/type.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,24 @@ type NewsCardProps = {
date: Date;
views: number;
};
type ArticleContentsProps = {
data: ArticleContentsType;
};
type ArticleContentsType = {
artcContents: string; // HTML 형식의 게시글 내용
artcTitle: string; // 게시글 제목
artcSeq: string; // 현재 게시글 순번
artcNextSeq: number; // 다음 게시글 순번
artcPrevSeq: number; // 이전 게시글 순번
boardCode: string; // 게시판 코드
boardCatSeq: number; // 게시판 카테고리 순번
maxArticlePerPage: number; // 페이지당 최대 게시글 수
imgFilePath: string; // 대표 이미지 경로
delYn: "Y" | "N"; // 삭제 여부
useYn: "Y" | "N"; // 사용 여부
viewCnt: number; // 조회수
regDttm: number; // 등록일시 (timestamp)
regr: string; // 등록자
updDttm: number; // 수정일시 (timestamp)
updr: string; // 수정자
};
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import PlayerCard from "./player-card";
import PlayerCard from "../player-card";

export function CoachList({ data }: CoachListProps) {
return (
Expand All @@ -10,6 +10,7 @@ export function CoachList({ data }: CoachListProps) {
image={coach.mobilePlayerImg1}
name={coach.playerName}
backnum={parseInt(coach.backnum)}
pathname="coach"
/>
))}
</div>
Expand Down
22 changes: 22 additions & 0 deletions components/player/pitcher/pitcher-detail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { PitcherStatsInfo } from "./pitcher-stats-info";
import { PitcherHistory } from "./pitcher-history";
import { PitcherProfileImage } from "./pitcher-profile-image";

export const PitcherDetail = ({ data }: PitcherDetailProps) => {
return (
<div className="bg-SYSTEM-white rounded-lg shadow-lg overflow-hidden border">
<div className="grid md:grid-cols-2">
{/* 투수 프로필이미지 */}
<PitcherProfileImage data={data} />
{/* 투수 스탯 */}
<div className="p-8 space-y-6">
<PitcherStatsInfo data={data} />
{/* 투수 경기이력 및 커리어 */}
<PitcherHistory data={data} />
</div>
</div>
</div>
);
};

export default PitcherDetail;
31 changes: 31 additions & 0 deletions components/player/pitcher/pitcher-history.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export const PitcherHistory = ({ data }: PitcherDetailProps) => {
return (
<>
<div className="border-t pt-4">
<h2 className="text-xl font-semibold mb-4">최근 경기 기록</h2>
<div className="grid grid-cols-2 gap-6">
<div className="bg-SYSTEM-main/5 rounded-lg p-4 text-center">
<p className="text-sm text-ELSE-49">볼넷</p>
<p className="text-2xl font-bold text-SYSTEM-main">
{data.seasonsummary.bb || "0"}
</p>
</div>
<div className="bg-SYSTEM-main/5 rounded-lg p-4 text-center">
<p className="text-sm text-ELSE-49">삼진</p>
<p className="text-2xl font-bold text-SYSTEM-main">
{data.seasonsummary.kk || "0"}
</p>
</div>
</div>
</div>

{/* Career */}
<div className="border-t pt-4">
<p className="text-ELSE-49">커리어</p>
<p className="text-sm text-ELSE-49 mt-1">
{data.gameplayer.career || "-"}
</p>
</div>
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import PlayerCard from "./player-card";
import PlayerCard from "../player-card";

export function PitcherList({ data }: PitchListProps) {
return (
Expand All @@ -10,6 +10,7 @@ export function PitcherList({ data }: PitchListProps) {
image={pitcher.mobilePlayerImg2}
name={pitcher.playerName}
backnum={parseInt(pitcher.backnum)}
pathname="pitcher"
/>
))}
</div>
Expand Down
40 changes: 40 additions & 0 deletions components/player/pitcher/pitcher-profile-image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Image from "next/image";

export const PitcherProfileImage = ({ data }: PitcherDetailProps) => {
return (
<>
<div className="flex items-center justify-center bg-SYSTEM-white">
<div
className="relative w-full
h-[300px]
md:h-[450px]
lg:h-[480px]
xl:h-[540px]
min-w-[280px]
max-w-[540px]
transition-all duration-300"
>
{data.gameplayer.playerPrvwImg ? (
<Image
src={data.gameplayer.playerPrvwImg}
alt={`${data.gameplayer.playerName} profile`}
fill
priority
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 450px, (max-width: 1280px) 480px, 540px"
className="object-contain"
/>
) : (
<div className="w-full h-full flex items-center justify-center bg-ELSE-DE">
<p className="text-ELSE-7374">이미지 없음</p>
</div>
)}
<div className="absolute top-0 left-2 bg-SYSTEM-white/90 rounded-full px-6 py-1 shadow-md z-10">
<span className="text-3xl font-bold text-SYSTEM-main">
# {data.gameplayer.backnum || "-"}
</span>
</div>
</div>
</div>
</>
);
};
Loading

0 comments on commit 759c618

Please sign in to comment.