dm_new: Lnb 제목 외
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
||||
// apps/dm/app/(landing)/reuse/apply/place/page.tsx
|
||||
// app/apply/dmdco/page.tsx
|
||||
"use client";
|
||||
|
||||
import { useMemo, useState } from "react";
|
||||
@@ -0,0 +1,229 @@
|
||||
// apps/dm/app/(landing)/reuse/business/globalCase/overview/page.tsx
|
||||
"use client";
|
||||
|
||||
import SubPageHeader from "@/components/SubPageHeader";
|
||||
import CaseImageSlider from "@/components/CaseImageSlider";
|
||||
|
||||
function SectionTitle({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="h-5 w-[3px] bg-sky-500" />
|
||||
<h3 className="text-2xl font-bold text-neutral-900">{children}</h3>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type HrProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
function Hr({ className = "" }: HrProps) {
|
||||
return <div className={`h-[2px] w-full bg-black/10 ${className}`} />;
|
||||
}
|
||||
|
||||
type ImgCardProps = {
|
||||
src: string;
|
||||
alt: string;
|
||||
};
|
||||
|
||||
function ImgCard({ src, alt }: ImgCardProps) {
|
||||
return (
|
||||
<div className="w-full overflow-x-auto">
|
||||
<img
|
||||
src={src}
|
||||
alt={alt}
|
||||
className="block mx-auto max-w-none"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function GreywaterPage() {
|
||||
return (
|
||||
<div className="bg-white">
|
||||
<SubPageHeader
|
||||
title="해외 재이용 사례 개요"
|
||||
crumbs={[
|
||||
{ label: "Home", href: "/reuse" },
|
||||
{ label: "물 재이용 사례" },
|
||||
{ label: "해외 재이용 사례" },
|
||||
{ label: "사례개요", href: "/reuse/business/globalCase/overview" },
|
||||
]}
|
||||
hideFooterLine
|
||||
hideGuideText
|
||||
wrapClassName="!pb-0"
|
||||
/>
|
||||
|
||||
<Hr className="my-7" />
|
||||
|
||||
{/* 슬라이드 이미지 영역 */}
|
||||
<CaseImageSlider
|
||||
className="mt-8"
|
||||
maxWidthClassName="max-w-[760px]"
|
||||
slides={[
|
||||
{ src: "/images/landing/business/globalCase/overview_01.png", alt: "해외 재이용 사례 1" },
|
||||
]}
|
||||
/>
|
||||
|
||||
<section className="mt-6">
|
||||
<div className="rounded-md bg-[#e9f0f1] p-8">
|
||||
<h3 className="text-xl font-bold text-gray-800 leading-relaxed">
|
||||
2024년 하수도 통계 기준 15.6%이며,<br />
|
||||
제2차 물 재이용 기본 계획을 고려한 2030년 목표는 <span className="font-extrabold">17%</span>
|
||||
</h3>
|
||||
|
||||
{/* 진행 바 영역 */}
|
||||
<div className="mt-6 space-y-4">
|
||||
{/* 2024 */}
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-sm text-gray-600">’24년도</span>
|
||||
<div className="relative h-7 rounded-r-lg">
|
||||
<div className="h-7 w-[112px] rounded-r-lg bg-gray-400" />
|
||||
</div>
|
||||
<span className="text-sm text-gray-700">15.6%</span>
|
||||
</div>
|
||||
|
||||
{/* 2030 */}
|
||||
<div className="flex items-center gap-4">
|
||||
<span className="text-sm text-gray-600">’30년도</span>
|
||||
<div className="relative">
|
||||
<div className="h-10 w-[327px] rounded-r-lg bg-gradient-to-r from-sky-500 to-green-500" />
|
||||
</div>
|
||||
<span className="text-xl font-bold text-gray-900">17%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 설명 문구 */}
|
||||
<ul className="mt-6 space-y-2 text-base text-gray-600">
|
||||
<li>
|
||||
• 우리나라의 하수 처리 재이용률은 <span className="text-sky-600 ">15% 수준</span>
|
||||
</li>
|
||||
<li>
|
||||
• 대만은 가뭄과 공업용수 증가에 대응하여
|
||||
<span className="text-sky-600 ">
|
||||
{" "}현재 4.3% 수준이며, 16.5%까지 확대 계획 수립
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{/* 테이블 */}
|
||||
<div className="mt-6">
|
||||
<table className="w-full text-center text-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="bg-[#C2CAD2] px-4 py-3 text-black rounded-t-lg">국가</th>
|
||||
<th className="bg-sky-600 px-4 py-3 text-white rounded-t-lg">해외정보</th>
|
||||
<th className="bg-teal-500 px-4 py-3 text-white rounded-t-lg">현재</th>
|
||||
<th className="bg-green-500 px-4 py-3 text-white rounded-t-lg">미래(목표, 예측치)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white border border-t-0">
|
||||
<tr className="border-t">
|
||||
<td className="px-4 py-3 font-medium">한국</td>
|
||||
<td className="px-4 py-3 bg-sky-50 text-gray-700">12.1%</td>
|
||||
<td className="px-4 py-3">15.6%</td>
|
||||
<td className="px-4 py-3 bg-sky-50 text-gray-700">17%</td>
|
||||
</tr>
|
||||
<tr className="border-t">
|
||||
<td className="px-4 py-3 font-medium">대만</td>
|
||||
<td className="px-4 py-3 bg-sky-50 text-gray-700">2.4%</td>
|
||||
<td className="px-4 py-3">4.3%</td>
|
||||
<td className="px-4 py-3 bg-sky-50 text-gray-700">16.5%</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Hr className="my-11" />
|
||||
|
||||
{/* 주요 국가의 하수처리수 재이용률 (%) */}
|
||||
<section className="pb-[200px]">
|
||||
<SectionTitle>주요 국가의 하수처리수 재이용률 (%)</SectionTitle>
|
||||
{/* 설명 문구 */}
|
||||
<ul className="mt-6 space-y-2 text-base text-gray-600">
|
||||
<li>
|
||||
• 전 세계적으로 물 재이용은 호주, 유럽, 아프리카, 미국 등 가뭄이 잦거나 심각한 가뭄이 발생한 국가에서 많이 이루어짐
|
||||
</li>
|
||||
<li>
|
||||
• 이스라엘, 쿠웨이트 등 중동 및 북아프리카 지역은 가용 수자원이 제한되어 있어 재이용량 비중도 매우 높은 편
|
||||
</li>
|
||||
</ul>
|
||||
{/* 테이블 (2단 병렬: 좌/우 데이터) */}
|
||||
<div className="mt-6">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="min-w-[900px] w-full text-center text-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
{/* 좌측 3컬럼 */}
|
||||
<th className="bg-[#C2CAD2] px-4 py-3 text-black rounded-t-lg">국가명</th>
|
||||
<th className="bg-sky-600 px-4 py-3 text-white rounded-t-lg">지역</th>
|
||||
<th className="bg-green-500 px-4 py-3 text-white rounded-t-lg">재이용률</th>
|
||||
|
||||
{/* 우측 3컬럼 */}
|
||||
<th className="bg-[#C2CAD2] px-4 py-3 text-black rounded-t-lg">국가명</th>
|
||||
<th className="bg-sky-600 px-4 py-3 text-white rounded-t-lg">지역</th>
|
||||
<th className="bg-green-500 px-4 py-3 text-white rounded-t-lg">재이용률</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody className="bg-white border border-t-0">
|
||||
{[
|
||||
{
|
||||
L: { c: "이스라엘", r: "중동&북아프리카", v: "92.3" },
|
||||
R: { c: "튀르키예", r: "동유럽&중앙아시아", v: "26.6" },
|
||||
},
|
||||
{
|
||||
L: { c: "쿠웨이트", r: "중동&북아프리카", v: "89.3" },
|
||||
R: { c: "독일", r: "서유럽", v: "25.0" },
|
||||
},
|
||||
{
|
||||
L: { c: "호주", r: "동아시아&태평양", v: "49.0" },
|
||||
R: { c: "스페인", r: "서유럽", v: "24.4" },
|
||||
},
|
||||
{
|
||||
L: { c: "싱가포르", r: "동아시아&태평양", v: "44.4" },
|
||||
R: { c: "한국", r: "동아시아&태평양", v: "12.1" },
|
||||
},
|
||||
{
|
||||
L: { c: "그리스", r: "서유럽", v: "39.1" },
|
||||
R: { c: "미국", r: "북아메리카", v: "13.1" },
|
||||
},
|
||||
{
|
||||
L: { c: "사우디아라비아", r: "중동&북아프리카", v: "32.8" },
|
||||
R: { c: "프랑스", r: "서유럽", v: "9.5" },
|
||||
},
|
||||
{
|
||||
L: { c: "이탈리아", r: "서유럽", v: "31.7" },
|
||||
R: { c: "대만", r: "동아시아&태평양", v: "2.4" },
|
||||
},
|
||||
{
|
||||
L: { c: "룩셈부르크", r: "서유럽", v: "29.1" },
|
||||
R: { c: "일본", r: "동아시아&태평양", v: "0.8" },
|
||||
},
|
||||
{
|
||||
L: { c: "포르투갈", r: "서유럽", v: "29.0" },
|
||||
R: { c: "", r: "", v: "" }, // 마지막 우측은 빈칸(이미지처럼)
|
||||
},
|
||||
].map((row, idx) => (
|
||||
<tr key={idx} className="border-t">
|
||||
{/* 좌측 */}
|
||||
<td className="px-4 py-3 font-medium text-gray-700">{row.L.c}</td>
|
||||
<td className="px-4 py-3 bg-sky-50 text-gray-700">{row.L.r}</td>
|
||||
<td className="px-4 py-3 bg-green-50 text-gray-700">{row.L.v}</td>
|
||||
|
||||
{/* 우측 */}
|
||||
<td className="px-4 py-3 font-medium text-gray-700">{row.R.c}</td>
|
||||
<td className="px-4 py-3 bg-sky-50 text-gray-700">{row.R.r}</td>
|
||||
<td className="px-4 py-3 bg-green-50 text-gray-700">{row.R.v}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -42,12 +42,12 @@ export default function GreywaterPage() {
|
||||
return (
|
||||
<div className="bg-white">
|
||||
<SubPageHeader
|
||||
title="수원시 황구지천 하천유지용수"
|
||||
title="구리시 도로자동청소시스템"
|
||||
crumbs={[
|
||||
{ label: "Home", href: "/reuse" },
|
||||
{ label: "물 재이용 사례" },
|
||||
{ label: "하수 재이용 사례" },
|
||||
{ label: "수원시 황구지천", href: "/reuse/business/sewage/hwanggu" },
|
||||
{ label: "구리시", href: "/reuse/business/sewage/guri" },
|
||||
]}
|
||||
hideFooterLine
|
||||
hideGuideText
|
||||
@@ -61,7 +61,8 @@ export default function GreywaterPage() {
|
||||
className="mt-8"
|
||||
maxWidthClassName="max-w-[760px]"
|
||||
slides={[
|
||||
{ src: "/images/landing/business/sewage/hwanggu_01.png", alt: "수원시 황구지천 하수 재이용 1" },
|
||||
{ src: "/images/landing/business/sewage/guri_01.png", alt: "구리시 도로자동청소시스템 1" },
|
||||
{ src: "/images/landing/business/sewage/guri_02.png", alt: "구리시 도로자동청소시스템 2" },
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -69,7 +70,7 @@ export default function GreywaterPage() {
|
||||
<section className="mt-6">
|
||||
<SectionTitle>사업명</SectionTitle>
|
||||
<p className="mt-8 text-base text-gray-600">
|
||||
수원시 황수원시 황구지천 하수처리수 재이용사업
|
||||
구리시 도로자동청소시스템 설치사업
|
||||
</p>
|
||||
</section>
|
||||
|
||||
@@ -79,7 +80,7 @@ export default function GreywaterPage() {
|
||||
<section className="mt-6">
|
||||
<SectionTitle>사업목적</SectionTitle>
|
||||
<p className="mt-8 text-base text-gray-600">
|
||||
황구지천 공공하수처리시설 하수처리수 재이용사업으로 향후 호매실천 및 금곡천 건천화 방지로 주민들에게 친수 공간 제공 및 하천 생태계 보전
|
||||
고농도 미세먼지 발생 및 폭염의 급증에 따라 공공하수처리시설 발생 재이용수 일부를 도로자동청소시스템에 활용하여 미세먼지 저감 및 폭염 취약성 완화
|
||||
</p>
|
||||
</section>
|
||||
|
||||
@@ -89,10 +90,10 @@ export default function GreywaterPage() {
|
||||
<section className="mt-6">
|
||||
<SectionTitle>사업 주요 내용</SectionTitle>
|
||||
<p className="mt-8 text-base text-gray-600">
|
||||
총사업비 : 110억원<br/>
|
||||
위 치 : 수원시 권선구 호매실천, 금곡천<br/>
|
||||
관 로 : 3.9km<br/>
|
||||
공 급 량 : 25,000㎥/일(하수처리시설 용량: 45,000㎥/일)<br/>
|
||||
총사업비 : 61억원<br/>
|
||||
위 치 : 구리시 경춘로 및 갈매중앙로 일대 등<br/>
|
||||
관 로 : 5.8km<br/>
|
||||
공급계획<br/>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
@@ -105,62 +106,38 @@ export default function GreywaterPage() {
|
||||
<div className="overflow-x-auto mt-8">
|
||||
<table className="w-full border border-[#E3E7EA] text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
{/* 구분 */}
|
||||
<th className="w-1/4 bg-[#E3E7EA] text-black font-semibold py-4 border border-gray-300">
|
||||
구분
|
||||
</th>
|
||||
|
||||
{/* 공급량 */}
|
||||
<th className="w-2/4 bg-[#1FA3C6] text-white font-semibold py-4 border border-gray-300">
|
||||
공급량
|
||||
</th>
|
||||
|
||||
{/* 비고 */}
|
||||
<th className="w-2/4 bg-[#72B84F] text-white font-semibold py-4 border border-gray-300">
|
||||
비고
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th className="bg-[#01ACE5] text-white font-semibold py-4 border border-gray-300">
|
||||
시설명
|
||||
</th>
|
||||
<th className="bg-[#33B5C8] text-white font-semibold py-4 border border-gray-300">
|
||||
재이용수 용도
|
||||
</th>
|
||||
<th className="bg-[#55BCA2] text-white font-semibold py-4 border border-gray-300">
|
||||
공급량(㎥/일)
|
||||
</th>
|
||||
<th className="bg-[#6DBB4F] text-white font-semibold py-4 border border-gray-300">
|
||||
원수
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
{/* 좌측 병합 */}
|
||||
<td
|
||||
rowSpan={3}
|
||||
className="bg-white font-medium text-gray-700 border border-gray-300"
|
||||
>
|
||||
하천 등 유지용수
|
||||
</td>
|
||||
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700 text-lg font-medium">
|
||||
12,500m³/일
|
||||
</td>
|
||||
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700">
|
||||
호매실천 공급
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700 text-lg font-medium">
|
||||
6,250m³/일
|
||||
</td>
|
||||
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700">
|
||||
금곡천1 공급
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700 text-lg font-medium">
|
||||
6,250m³/일
|
||||
</td>
|
||||
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700">
|
||||
금곡천2 공급
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
className="bg-white py-6 border border-gray-300 text-gray-700"
|
||||
>
|
||||
도로자동청소시스템
|
||||
</td>
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700">
|
||||
세척살수용수
|
||||
</td>
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700">
|
||||
178
|
||||
</td>
|
||||
<td className="bg-white py-6 border border-gray-300 text-gray-700">
|
||||
구리 공공하수처리장 재이용수
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -62,6 +62,8 @@ export default function GreywaterPage() {
|
||||
maxWidthClassName="max-w-[760px]"
|
||||
slides={[
|
||||
{ src: "/images/landing/business/sewage/hwanggu_01.png", alt: "수원시 황구지천 하수 재이용 1" },
|
||||
{ src: "/images/landing/business/sewage/hwanggu_02.png", alt: "수원시 황구지천 하수 재이용 2" },
|
||||
{ src: "/images/landing/business/sewage/hwanggu_03.png", alt: "수원시 황구지천 하수 재이용 3" },
|
||||
]}
|
||||
/>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import "./globals.css";
|
||||
import { setCookie } from "../src/shared/lib";
|
||||
|
||||
setCookie("site-id-key", process.env.NEXT_PUBLIC_SITE_ID || "DN");
|
||||
setCookie("site-id-key", process.env.NEXT_PUBLIC_SITE_ID || "DM");
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function Cases() {
|
||||
|
||||
<div className="mt-14">
|
||||
<a
|
||||
href="#"
|
||||
href="/reuse/cases/rain"
|
||||
className="
|
||||
inline-flex items-center justify-center gap-3
|
||||
w-[260px] h-[52px]
|
||||
|
||||
@@ -349,22 +349,40 @@ function normalizeMenus(items: MenuItem[]): MenuItem[] {
|
||||
}));
|
||||
}
|
||||
|
||||
export const REUSE_SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "DN";
|
||||
export const REUSE_SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "DM";
|
||||
const anonymousMenuCache = new Map<string, MenuItem[]>();
|
||||
const anonymousMenuInFlight = new Map<string, Promise<MenuItem[]>>();
|
||||
|
||||
export async function fetchAnonymousMenu(siteId = REUSE_SITE_ID): Promise<MenuItem[]> {
|
||||
const response = await fetch(`/cms-service/api/v1/menu/anonymous/user/${siteId}`, {
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
cache: "no-store",
|
||||
});
|
||||
const cached = anonymousMenuCache.get(siteId);
|
||||
if (cached) return cached;
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load menu: ${response.status}`);
|
||||
const inFlight = anonymousMenuInFlight.get(siteId);
|
||||
if (inFlight) return inFlight;
|
||||
|
||||
const request = (async () => {
|
||||
const response = await fetch(`/cms-service/api/v1/menu/anonymous/user/${siteId}`, {
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
cache: "no-store",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load menu: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as MenuItem[];
|
||||
const normalized = Array.isArray(data) ? normalizeMenus(data) : [];
|
||||
anonymousMenuCache.set(siteId, normalized);
|
||||
return normalized;
|
||||
})();
|
||||
|
||||
anonymousMenuInFlight.set(siteId, request);
|
||||
try {
|
||||
return await request;
|
||||
} finally {
|
||||
anonymousMenuInFlight.delete(siteId);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as MenuItem[];
|
||||
if (!Array.isArray(data)) return [];
|
||||
return normalizeMenus(data);
|
||||
}
|
||||
|
||||
function isPathMatched(pathname: string, urlPath: string) {
|
||||
@@ -372,11 +390,14 @@ function isPathMatched(pathname: string, urlPath: string) {
|
||||
return pathname === urlPath || pathname.startsWith(`${urlPath}/`);
|
||||
}
|
||||
|
||||
function hasMatchedPathInTree(menu: MenuItem, pathname: string): boolean {
|
||||
if (isPathMatched(pathname, menu.urlPath)) return true;
|
||||
return (menu.children ?? []).some((child) => hasMatchedPathInTree(child, pathname));
|
||||
}
|
||||
|
||||
export function findActiveTopMenu(menus: MenuItem[], pathname: string): MenuItem | null {
|
||||
const level1Menus = menus.filter((menu) => menu.levelNo === 1 || menu.parentId === null);
|
||||
const matched = level1Menus
|
||||
.filter((menu) => isPathMatched(pathname, menu.urlPath))
|
||||
.sort((a, b) => b.urlPath.length - a.urlPath.length);
|
||||
const matched = level1Menus.filter((menu) => hasMatchedPathInTree(menu, pathname));
|
||||
|
||||
return matched[0] ?? level1Menus[0] ?? null;
|
||||
}
|
||||
@@ -475,21 +496,7 @@ export const CommonReducer:(set:any)=>CommonAction=(set: any) => {
|
||||
}
|
||||
})
|
||||
)},
|
||||
fetchAnonymousMenu: async (siteId = REUSE_SITE_ID) => {
|
||||
const response = await fetch(`/cms-service/api/v1/menu/anonymous/user/${siteId}`, {
|
||||
method: "GET",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
cache: "no-store",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load menu: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as MenuItem[];
|
||||
if (!Array.isArray(data)) return [];
|
||||
return normalizeMenus(data);
|
||||
}
|
||||
fetchAnonymousMenu: async (siteId = REUSE_SITE_ID) => fetchAnonymousMenu(siteId)
|
||||
}
|
||||
}
|
||||
export type CommonStore = CommonType & CommonAction;
|
||||
|
||||
@@ -33,7 +33,7 @@ export const StoreZus = (
|
||||
) => {
|
||||
return createStore<DmStore>()((set) => {
|
||||
if (typeof window !== "undefined") {
|
||||
tokenManager.setToken("site-id-key", "DM");
|
||||
tokenManager.setToken("site-id-key", process.env.NEXT_PUBLIC_SITE_ID||"DM");
|
||||
tokenManager.setToken("site-theme-key", "green");
|
||||
}
|
||||
|
||||
|
||||
@@ -69,21 +69,42 @@ const MOCK: Record<TabKey, CaseItem[]> = {
|
||||
title: "경기도 파주시 하수 재이용",
|
||||
desc: "운정·금촌하수처리시설의 하수처리수를 막공법(U/F, R/O)으로 재처리하여 파주 LCD 산업단지내 3개 업체*에...",
|
||||
imageSrc: "/images/landing/sewage_01.png",
|
||||
href: "#",
|
||||
href: "/reuse/business/sewage/paju",
|
||||
},
|
||||
{
|
||||
id: "sewage-2",
|
||||
title: "충남보령 하수재이용",
|
||||
desc: "보령·신보령화력발전소에 하루 1만톤의 탈황용수 공급을 위해 보령하수처리시설의 하수처리수 재이용 사업...",
|
||||
imageSrc: "/images/landing/sewage_02.png",
|
||||
href: "#",
|
||||
href: "/reuse/business/sewage/bolyeong",
|
||||
},
|
||||
{
|
||||
id: "sewage-3",
|
||||
title: "여수시 하수처리수 재이용",
|
||||
desc: "(빗물) 월드컵경기장 등 4개소에 노면 빗물분사시스템 및 빗물 공급기를 설치하여 혹서기 도시 열섬효과 및 도로...",
|
||||
imageSrc: "/images/landing/sewage_03.png",
|
||||
href: "#",
|
||||
href: "/reuse/business/sewage/yeosu",
|
||||
},
|
||||
{
|
||||
id: "sewage-4",
|
||||
title: "청주시 하수 재이용 시설",
|
||||
desc: "청주시 하수처리수 재이용 민간투자사업(BTO) 청주시 하수처리수 재이용 민간투자사업(BTO) 청주시 하수처리수 재이용 민간투자사업(BTO)...",
|
||||
imageSrc: "/images/landing/sewage_04.png",
|
||||
href: "/reuse/business/sewage/cheongju",
|
||||
},
|
||||
{
|
||||
id: "sewage-5",
|
||||
title: "수원시 황구지천 하천유지용수",
|
||||
desc: "황구지천 공공하수처리시설 하수처리수 재이용사업으로 향후 호매실천 및 금곡천 건천화 방지로...",
|
||||
imageSrc: "/images/landing/sewage_05.png",
|
||||
href: "/reuse/business/sewage/hwanggu",
|
||||
},
|
||||
{
|
||||
id: "sewage-6",
|
||||
title: "구리시 도로자동청소시스템",
|
||||
desc: "고농도 미세먼지 발생 및 폭염의 급증에 따라 공공하수처리시설 발생 재이용수 일부를 도로자동청소시스템에 활용...",
|
||||
imageSrc: "/images/landing/sewage_06.png",
|
||||
href: "/reuse/business/sewage/guri",
|
||||
},
|
||||
...Array.from({ length: 6 }).map((_, i) => ({
|
||||
id: `sewage-x-${i}`,
|
||||
|
||||
@@ -70,7 +70,7 @@ export default function Lnb() {
|
||||
return (
|
||||
<aside className="w-[260px]">
|
||||
<div className="flex h-[120px] items-center justify-center bg-gradient-to-r from-cyan-500 to-green-500 text-[40px] font-bold text-white">
|
||||
{currentTopMenu?.menuKornNm ?? ""}
|
||||
{currentTopMenu?.menuKornNm?.trim().split(/\s+/).pop() ?? ""}
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// apps/dm/app/(landing)/reuse/_components/LoginStatus.tsx
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function LoginStatus() {
|
||||
const router = useRouter();
|
||||
const [userName, setUserName] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// 예시: 로그인 시 저장한 값
|
||||
const name = localStorage.getItem("userName");
|
||||
setUserName(name);
|
||||
}, []);
|
||||
|
||||
const handleLogout = () => {
|
||||
localStorage.removeItem("accessToken");
|
||||
localStorage.removeItem("userName");
|
||||
router.refresh(); // 헤더 상태 갱신
|
||||
};
|
||||
|
||||
// 🔹 로그인 전
|
||||
if (!userName) {
|
||||
return (
|
||||
<Link
|
||||
href="/reuse/login"
|
||||
className="flex items-center gap-2 rounded-md bg-sky-500 px-4 py-2 text-sm font-medium text-white hover:bg-sky-600"
|
||||
>
|
||||
로그인
|
||||
<span>→</span>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
// 🔹 로그인 후
|
||||
return (
|
||||
<div className="flex items-center gap-3 text-sm">
|
||||
<span className="text-gray-700">
|
||||
<strong>{userName}</strong>님 환영합니다.
|
||||
</span>
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="rounded-md bg-red-500 px-3 py-2 text-white hover:bg-red-600"
|
||||
>
|
||||
로그아웃
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -11,10 +11,10 @@ const LS_TOKEN_KEY = "reuse_accessToken";
|
||||
const LS_USER_KEY = "reuse_userName";
|
||||
|
||||
const DEFAULT_NAV_ITEMS: Pick<MenuItem, "menuCd" | "menuKornNm" | "urlPath" | "newWndwYn">[] = [
|
||||
{ menuCd: 1, menuKornNm: "Intro", urlPath: "/reuse/intro/law", newWndwYn: "N" },
|
||||
{ menuCd: 2, menuKornNm: "Status", urlPath: "/reuse/cases/rain", newWndwYn: "N" },
|
||||
{ menuCd: 3, menuKornNm: "Business", urlPath: "/reuse/business/rain/suwon", newWndwYn: "N" },
|
||||
{ menuCd: 4, menuKornNm: "Demand", urlPath: "/reuse/apply/place", newWndwYn: "N" },
|
||||
{ menuCd: 1, menuKornNm: "물 재이용 소개", urlPath: "/reuse/intro/law", newWndwYn: "N" },
|
||||
{ menuCd: 2, menuKornNm: "물 재이용 현황", urlPath: "/reuse/cases/rain", newWndwYn: "N" },
|
||||
{ menuCd: 3, menuKornNm: "물 재이용 사례", urlPath: "/reuse/business/rain/suwon", newWndwYn: "N" },
|
||||
{ menuCd: 4, menuKornNm: "수요신청", urlPath: "/reuse/apply/place", newWndwYn: "N" },
|
||||
];
|
||||
|
||||
export default function TopNav() {
|
||||
@@ -78,17 +78,20 @@ export default function TopNav() {
|
||||
return (
|
||||
<>
|
||||
<header className="fixed left-0 right-0 top-0 z-50 border-b bg-white shadow-md backdrop-blur">
|
||||
{/* ✅ 좌/중/우 정렬이 되도록 컨테이너 구성 */}
|
||||
<div className="px-6">
|
||||
<div className="relative flex h-[83px] items-center justify-between">
|
||||
{/* 좌측: 로고 */}
|
||||
<div className="flex items-center gap-3">
|
||||
<Link href="/main" className="flex items-center">
|
||||
<img src="/images/landing/logo.png" alt="HASUON" className="h-9 w-auto" />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* 중앙: 상단 메뉴 */}
|
||||
<nav className="absolute left-1/2 flex -translate-x-1/2 items-center gap-[40px] text-sm font-medium">
|
||||
{navItems.map((item) => {
|
||||
const requiresLogin = (item.urlPath)? item.urlPath.startsWith("/reuse/apply") : false;
|
||||
const requiresLogin = (item.urlPath)? item.urlPath.startsWith("/apply") : false;
|
||||
const active = isMenuActive(pathname, item);
|
||||
const className = [
|
||||
"relative px-3 py-2 text-lg font-bold",
|
||||
@@ -129,6 +132,7 @@ export default function TopNav() {
|
||||
})}
|
||||
</nav>
|
||||
|
||||
{/* ✅ 우측: 로그인 버튼 / 로그인 정보 + 로그아웃 */}
|
||||
<div className="flex items-center gap-3">
|
||||
{!userName ? (
|
||||
<button
|
||||
@@ -136,7 +140,7 @@ export default function TopNav() {
|
||||
onClick={openLogin}
|
||||
className="inline-flex items-center gap-2 rounded-md bg-sky-500 px-4 py-2 text-base text-white hover:bg-sky-600"
|
||||
>
|
||||
Login
|
||||
로그인
|
||||
<span aria-hidden>
|
||||
<img
|
||||
src="/images/landing/icon_login.png"
|
||||
@@ -148,14 +152,14 @@ export default function TopNav() {
|
||||
) : (
|
||||
<>
|
||||
<span className="text-base text-gray-700">
|
||||
<strong className="text-xl text-emerald-600">{userName}</strong>
|
||||
<strong className="text-xl text-emerald-600">{userName}</strong>님 환영합니다.
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={logout}
|
||||
className="inline-flex items-center gap-2 rounded-md bg-red-500 px-4 py-2 text-base text-white hover:bg-red-600"
|
||||
>
|
||||
Logout
|
||||
로그아웃
|
||||
<span aria-hidden>
|
||||
<img
|
||||
src="/images/landing/icon_logout.png"
|
||||
|
||||
Reference in New Issue
Block a user