Compare commits

...
7 Commits
Author SHA1 Message Date
swcho 40cbd827e2 Merge remote-tracking branch 'origin/main' into iipbs/sn/dev 2025-12-12 11:13:15 +09:00
jcchoi ecc0b7a459 Merge branch 'main' of https://www.onasys.co.kr:3000/ONAANDALL/frontend 2025-12-12 11:05:21 +09:00
jcchoi 56d8f7445e 포탈 데시보드 기능 2025-12-12 10:59:59 +09:00
jcchoi b25e89099d Next.js 15.3.8 업데이트트 2025-12-12 10:35:10 +09:00
jcchoi 6a3aa5750d 타이틀 제거 2025-12-11 21:12:48 +09:00
jcchoi b04c215503 layout 교정 2025-12-11 21:10:34 +09:00
jcchoi 5ff12b9cbb layout 정리리 2025-12-11 21:02:25 +09:00
28 changed files with 386 additions and 139 deletions
+1 -1
View File
@@ -34,7 +34,7 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lucide-react": "^0.474.0", "lucide-react": "^0.474.0",
"next": "15.3.6", "next": "15.3.8",
"next-qrcode": "^2.5.1", "next-qrcode": "^2.5.1",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"react-chartjs-2": "^5.3.0", "react-chartjs-2": "^5.3.0",
@@ -11,9 +11,11 @@ import {
type MyPostList, type MyPostList,
type PostParams, type PostParams,
type MyPostParams, type MyPostParams,
type NoticePostParams,
type PostFormData, type PostFormData,
type PostUpdateFormData, type PostUpdateFormData,
type PostService, type PostService,
type NoticePostList,
} from "../model/post-interface"; } from "../model/post-interface";
export class PostApiService implements PostService { export class PostApiService implements PostService {
@@ -28,6 +30,17 @@ export class PostApiService implements PostService {
return response.data; return response.data;
} }
public async getNoticePostList(
params?: NoticePostParams,
): Promise<NoticePostList> {
const response = await client.get<NoticePostList>(
`${ENDPOINT.BOARD_SERVICE.POSTS}/recentPosts`,
{ params },
);
return response.data;
}
public async getMyPostList( public async getMyPostList(
params?: MyPostParams, params?: MyPostParams,
): Promise<MyPostList> { ): Promise<MyPostList> {
+2
View File
@@ -4,11 +4,13 @@ export {
postUpdateFormSchema, postUpdateFormSchema,
type Post, type Post,
type MyPost, type MyPost,
type NoticePost,
type MovePost, type MovePost,
type DeletePost, type DeletePost,
type PostList, type PostList,
type PostParams, type PostParams,
type MyPostParams, type MyPostParams,
type NoticePostParams,
type PostFormData, type PostFormData,
type PostUpdateFormData, type PostUpdateFormData,
type PostService, type PostService,
@@ -12,6 +12,20 @@ export interface PostParams extends PageableParams {
ansUseYn?: string; ansUseYn?: string;
} }
export interface NoticePostParams extends PageableParams {
keywordType?: string;
keyword?: string;
bbsId?: number | null;
delYn?: string;
frDateYmd?: string;
toDateYmd?: string;
}
export interface NoticePost extends Post {
bbsNm: string;
bbsTypeCd: string;
}
export interface MyPostParams extends PageableParams { export interface MyPostParams extends PageableParams {
keywordType?: string; keywordType?: string;
keyword?: string; keyword?: string;
@@ -99,6 +113,7 @@ export const postUpdateFormSchema = postFormSchema.omit({
export type PostList = PageableList<Post>; export type PostList = PageableList<Post>;
export type MyPostList = PageableList<MyPost>; export type MyPostList = PageableList<MyPost>;
export type NoticePostList = PageableList<NoticePost>;
export type PostFormData = z.infer<typeof postFormSchema>; export type PostFormData = z.infer<typeof postFormSchema>;
export type PostUpdateFormData = z.infer<typeof postUpdateFormSchema>; export type PostUpdateFormData = z.infer<typeof postUpdateFormSchema>;
+34
View File
@@ -0,0 +1,34 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
export interface Banner {
bnrSn: number;
bnrTypeCd: string;
bnrTypeNm: string;
bnrTtl: string;
lnkgUrlAddr: string;
useYn: string;
atflCd: string;
mdfcnDt: string;
mdfr: string;
mdfrNm: string;
}
export const getBannerList = async (siteId: string) => {
const response = await client.get<Banner[]>(
`${ENDPOINT.CMS_SERVICE.BANNERS}/${siteId}`,
);
return response.data;
};
export const getImageUrlByAtflCd = async (atflCd: string): Promise<string> => {
if (!atflCd) return "";
const response = await client.get<Blob>(
`${ENDPOINT.ATTACH_SERVICE.IMAGES}/atflCd/${atflCd}`,
{
responseType: "blob",
},
);
const blob = response.data;
return URL.createObjectURL(blob);
};
@@ -348,85 +348,79 @@ export function KoreaBasinMap() {
// 스타일은 필요에 따라 tailwind, css 등으로 커스터마이즈하세요. // 스타일은 필요에 따라 tailwind, css 등으로 커스터마이즈하세요.
return ( return (
<div className="col-span-3 h-200 !p-0 relative z-10"> <div
<div className="card card-border"> ref={stageRef}
<div className="card-header text-foreground"> id="stage"
<h3 className="text-2xl font-medium">유역별 정보</h3> style={
</div> {
<div aspectRatio: 0.72/1,
ref={stageRef} width: "100%",
id="stage" maxHeight: "100%",
style={ position: "relative",
{ margin: "auto",
width: "100%", "--map-inset": "0%",
height: "560px", } as React.CSSProperties
position: "relative", }
zIndex: 20, >
"--map-inset": "0", <div
} as React.CSSProperties className={styles.bgLayer}
} id="bgLayer"
> />
<div <div
className={styles.bgLayer} ref={svgLayerRef}
id="bgLayer" id="svgLayer"
/> className={`${styles.svgLayer} ${styles.svgContainer}`}
<div style={{ width: "100%", height: "100%" }}
ref={svgLayerRef} />
id="svgLayer" <div
className={`${styles.svgLayer} ${styles.svgContainer}`} ref={labelsLayerRef}
style={{ width: "100%", height: "100%" }} id="labelsLayer"
/> className={styles.labelsLayer}
<div style={{
ref={labelsLayerRef} position: "absolute",
id="labelsLayer" left: 0,
className={styles.labelsLayer} top: 0,
style={{ width: "100%",
position: "absolute", height: "100%",
left: 0, pointerEvents: "none",
top: 0, }}
width: "100%", />
height: "100%", <div
pointerEvents: "none", ref={badgeRef}
}} id="badge"
/> className={styles.badge}
<div style={{ position: "absolute", zIndex: 10, display: "block" }}
ref={badgeRef} />
id="badge" <div
className={styles.badge} ref={popupRef}
style={{ position: "absolute", zIndex: 10, display: "block" }} id="popup"
/> className={styles.popup}
<div style={{
ref={popupRef} position: "absolute",
id="popup" zIndex: 20,
className={styles.popup} background: "#fff",
style={{ border: "1px solid #ccc",
position: "absolute", borderRadius: 8,
zIndex: 20, padding: 12,
background: "#fff", minWidth: 160,
border: "1px solid #ccc", boxShadow: "0 2px 8px #0002",
borderRadius: 8, display: "block",
padding: 12, opacity: 0,
minWidth: 160, visibility: "hidden",
boxShadow: "0 2px 8px #0002", }}
display: "block", >
opacity: 0, <table style={{ width: "100%" }}>
visibility: "hidden", <thead>
}} <tr>
> <th>구분</th>
<table style={{ width: "100%" }}> <th ref={colTitleRef} id="colTitle">
<thead> 시설수
<tr> </th>
<th>구분</th> </tr>
<th ref={colTitleRef} id="colTitle"> </thead>
시설수 <tbody ref={rowsRef} id="rows"></tbody>
</th> </table>
</tr>
</thead>
<tbody ref={rowsRef} id="rows"></tbody>
</table>
</div>
</div>
</div> </div>
</div> </div>
); );
} }
@@ -1,9 +1,9 @@
import dayjs from "dayjs"; import dayjs from "dayjs";
import type { ColumnDef } from "@tanstack/react-table"; import type { ColumnDef } from "@tanstack/react-table";
import { Badge } from "@common/components"; import { Badge } from "@common/components";
import type { Post, MyPost } from "@/entities/post"; import type { MyPost, NoticePost } from "@/entities/post";
const noticePostTableColumns: ColumnDef<Post>[] = [ const noticePostTableColumns: ColumnDef<NoticePost>[] = [
{ {
header: "번호", header: "번호",
cell: ({ row, table }) => { cell: ({ row, table }) => {
@@ -0,0 +1,106 @@
"use client";
import { useRef } from "react";
import { useQuery } from "@tanstack/react-query";
import Autoplay from "embla-carousel-autoplay";
import { ENDPOINT } from "@/shared/config";
import { getImageUrlByAtflCd, getBannerList } from "../api/banner";
import { getCookie } from "@/shared/lib";
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@common/components";
type BannerImageProps = {
atflCd: string;
bnrSn: number;
lnkgUrlAddr: string;
};
const BannerList: React.FC = () => {
const siteId = getCookie("site-id-key") ?? "";
const BannerImage = ({ atflCd, bnrSn, lnkgUrlAddr }: BannerImageProps) => {
const { data: imageUrl, isLoading } = useQuery({
queryKey: [ENDPOINT.ATTACH_SERVICE.IMAGES, atflCd],
queryFn: () => getImageUrlByAtflCd(atflCd),
enabled: !!atflCd,
});
const handleClick = () => {
if (lnkgUrlAddr) {
window.open(lnkgUrlAddr, '_blank');
}
};
if (isLoading) {
return (
<div className="relative flex h-24 items-center justify-center bg-accent mx-auto">
<div className="text-sm text-muted-foreground">로딩 중...</div>
</div>
);
}
if (!imageUrl) {
return (
<div className="relative flex h-24 items-center justify-center bg-accent mx-auto">
<div className="text-sm text-muted-foreground">이미지 없음</div>
</div>
);
}
return (
<div
className="relative flex h-24 items-center justify-center cursor-pointer hover:opacity-80 transition-opacity mx-auto"
onClick={handleClick}
>
<img src={imageUrl} className="object-contain w-full h-full" alt="배너 이미지" />
</div>
);
};
const { data: bannerList } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.BANNERS, siteId],
queryFn: () => getBannerList(siteId),
});
const plugin = useRef(Autoplay({ delay: 2000, stopOnInteraction: true }));
return (
<div className="card card-border">
<Carousel
plugins={[plugin.current]}
opts={{ loop: true }}
className="relative my-8 h-24"
>
<CarouselContent>
{bannerList && bannerList.length > 0 ? (
bannerList.map((banner) => (
<CarouselItem key={`banner-${banner.bnrSn}`} className="basis-1/3">
<BannerImage
atflCd={banner.atflCd}
bnrSn={banner.bnrSn}
lnkgUrlAddr={banner.lnkgUrlAddr}
/>
</CarouselItem>
))
) : (
<CarouselItem className="basis-1/3">
<div className="relative flex h-24 w-full items-center justify-center bg-accent">
<div className="text-sm text-muted-foreground">배너가 없습니다</div>
</div>
</CarouselItem>
)}
</CarouselContent>
<CarouselPrevious className="absolute left-2 top-1/2 !bg-[rgba(255,255,255,0.8)] text-accent-foreground z-10" />
<CarouselNext className="absolute right-2 top-1/2 !bg-[rgba(255,255,255,0.8)] text-accent-foreground z-10" />
</Carousel>
</div>
);
};
export default BannerList;
@@ -2,6 +2,7 @@
import React from "react"; import React from "react";
import { import {
cn,
Select, Select,
SelectContent, SelectContent,
SelectItem, SelectItem,
@@ -12,14 +13,19 @@ import {
interface BasinSelectProps { interface BasinSelectProps {
selectedBasin: string; selectedBasin: string;
onValueChange: (value: string) => void; onValueChange: (value: string) => void;
className?: string;
} }
const BasinSelect: React.FC<BasinSelectProps> = ({ selectedBasin, onValueChange }) => { const BasinSelect: React.FC<BasinSelectProps> = ({
selectedBasin,
onValueChange,
className
}) => {
const basins = ["한강", "금강", "낙동강", "영산강"]; const basins = ["한강", "금강", "낙동강", "영산강"];
return ( return (
<Select value={selectedBasin} onValueChange={onValueChange}> <Select value={selectedBasin} onValueChange={onValueChange}>
<SelectTrigger className="w-[100px] h-8 bg-blue-500 text-white font-bold text-md border-none hover:bg-blue-600"> <SelectTrigger className={cn("w-[12rem]", className)}>
<SelectValue placeholder="유역 선택" /> <SelectValue placeholder="유역 선택" />
</SelectTrigger> </SelectTrigger>
<SelectContent> <SelectContent>
@@ -24,6 +24,8 @@ import FoFcltCntRt from "./fo-fclt-cnt-rt";
import FoWqltInflEffl from "./fo-wqlt-Infl-effl"; import FoWqltInflEffl from "./fo-wqlt-Infl-effl";
import ReuseChart from "./reuse-chart"; import ReuseChart from "./reuse-chart";
import ReuseStatus from "./reuse-status"; import ReuseStatus from "./reuse-status";
import NoticeList from "./notice-list";
import BannerList from "./banner-list";
// Chart.js 등록 // Chart.js 등록
ChartJS.register( ChartJS.register(
@@ -137,9 +139,16 @@ function DashboardPage() {
</div> </div>
{/* 지도영역 */} {/* 지도영역 */}
<KoreaBasinMap /> <div className="col-span-3 !p-0 relative z-10" style={{ height: "765px", background: "rgba(255, 255, 255, 0.6)" }}>
<div className="card card-border" style={{ height: "100%" }}>
<div className="card-header text-foreground">
<h3 className="text-2xl font-medium">유역별 정보</h3>
</div>
<div id="mapArea" style={{height: "calc(100% - 40px)"}}>
<KoreaBasinMap />
</div>
</div>
</div>
{/* 사용자 정보 카드 */} {/* 사용자 정보 카드 */}
<div className="card card-border col-span-1 h-80 p-10"> <div className="card card-border col-span-1 h-80 p-10">
@@ -191,16 +200,12 @@ function DashboardPage() {
</div> </div>
</div> </div>
<div className="card card-border"> <div className="card card-border">
<div className="card-header text-foreground"> <NoticeList />
<h3 className="text-2xl font-medium">공지사항</h3>
</div>
<div className="h-70 p-4">
</div>
</div> </div>
{/* 배너 영역 */} {/* 배너 영역 */}
<div className="card card-border"> <div className="card card-border">
<BannerList />
</div> </div>
</div> </div>
</div> </div>
@@ -52,7 +52,7 @@ const FoFcltCntRt: React.FC = () => {
}, [operFcltStatus, selectedBasin]); }, [operFcltStatus, selectedBasin]);
return ( return (
<div className="card card-border"> <div className="card card-border" style={{ height: "250px" }}>
<div className="card-header text-foreground"> <div className="card-header text-foreground">
<h3 className="text-2xl font-medium">수계별 시설운영 개소수 및 가동률</h3> <h3 className="text-2xl font-medium">수계별 시설운영 개소수 및 가동률</h3>
<BasinSelect selectedBasin={selectedBasin} onValueChange={setSelectedBasin} /> <BasinSelect selectedBasin={selectedBasin} onValueChange={setSelectedBasin} />
@@ -189,7 +189,7 @@ const FoWqltInflEffl: React.FC = () => {
}; };
return ( return (
<div className="card card-border"> <div className="card card-border" style={{ height: "250px" }}>
<div className="card-header text-foreground"> <div className="card-header text-foreground">
<h3 className="text-2xl font-medium">수계별 유입ㆍ방류수질 분석</h3> <h3 className="text-2xl font-medium">수계별 유입ㆍ방류수질 분석</h3>
<BasinSelect selectedBasin={selectedBasin} onValueChange={setSelectedBasin} /> <BasinSelect selectedBasin={selectedBasin} onValueChange={setSelectedBasin} />
@@ -0,0 +1,53 @@
"use client";
import { useRouter } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import { getCoreRowModel } from "@tanstack/react-table";
import { PostApi, type NoticePost } from "@/entities/post";
import { ENDPOINT } from "@/shared/config";
import { useDataTable } from "@/shared/lib";
import {
noticePostTableColumns,
} from "../model/table-columns";
const NoticeList: React.FC = () => {
const router = useRouter();
const noticePostQuery = useQuery({
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS],
queryFn: () =>
PostApi.getNoticePostList({
page: 0,
size: 5,
keywordType: "bbsTypeCd",
keyword: "BBSNOTICE",
}),
});
const handleNoticePostRowClick = (row: NoticePost) => {
router.push(`/bbs/bbsnotice/${row.bbsId}/${row.pstNo}`);
};
const { tableComponent: noticePostTableComponent } = useDataTable({
query: noticePostQuery,
tableOptions: {
columns: noticePostTableColumns,
getCoreRowModel: getCoreRowModel(),
},
dataTableOptions: {
variant: "line",
onRowClick: handleNoticePostRowClick,
},
});
return (
<div className="card card-border !p-0">
<div className="card-header !m-0 !border-none text-foreground">
<h3 className="text-2xl font-medium">공지사항</h3>
</div>
{noticePostTableComponent}
</div>
);
};
export default NoticeList;
@@ -176,10 +176,10 @@ const ReuseChart: React.FC = () => {
}; };
return ( return (
<div className="card card-border"> <div className="card card-border" style={{ height: "250px" }}>
<div className="card-header text-foreground"> <div className="card-header text-foreground">
<h3 className="text-2xl font-medium">{chartItems[activeIndex]?.title}</h3> <h3 className="text-2xl font-medium">{chartItems[activeIndex]?.title}</h3>
<Button variant="outline" size="sm" className="text-white h-8 py-0 ml-auto">더보기</Button> <Button className="h-[3.2rem]">더보기</Button>
</div> </div>
<div className="h-60 p-4 relative overflow-hidden"> <div className="h-60 p-4 relative overflow-hidden">
<div <div
@@ -27,10 +27,10 @@ const ReuseStatus: React.FC = () => {
}; };
return ( return (
<div className="card card-border"> <div className="card card-border" style={{ height: "250px" }}>
<div className="card-header text-foreground"> <div className="card-header text-foreground">
<h3 className="text-2xl font-medium">물재이용 현황 (재이용량, m³)</h3> <h3 className="text-2xl font-medium">물재이용 현황 (재이용량, m³)</h3>
<Button variant="outline" size="sm" className="text-white h-8 py-0 ml-auto">더보기</Button> <Button className="h-[3.2rem]">더보기</Button>
</div> </div>
<div className="h-70 p-4"> <div className="h-70 p-4">
<div className="w-full h-full flex items-center justify-center"> <div className="w-full h-full flex items-center justify-center">
@@ -165,10 +165,10 @@ export default function SnOldPpl() {
}; };
return ( return (
<div className="card card-border"> <div className="card card-border" style={{ height: "250px" }}>
<div className="card-header text-foreground"> <div className="card-header text-foreground">
<h3 className="text-2xl font-medium">노후 하수관로 현황</h3> <h3 className="text-2xl font-medium">노후 하수관로 현황</h3>
<Button variant="outline" size="sm" className="text-white h-8 py-0 ml-auto">더보기</Button> <Button className="h-[3.2rem]">더보기</Button>
</div> </div>
<div className="h-70 p-0 flex items-center justify-center"> <div className="h-70 p-0 flex items-center justify-center">
<div style={{ width: "100%", maxWidth: 400, height: 131 }}> <div style={{ width: "100%", maxWidth: 400, height: 131 }}>
@@ -187,10 +187,11 @@ export default function SnPplStatus() {
//const data = { labels, datasets }; //const data = { labels, datasets };
return ( return (
<div className="card card-border"> <div className="card card-border" style={{ height: "250px" }}>
<div className="card-header text-foreground"> <div className="card-header text-foreground">
<h3 className="text-2xl font-medium">오수관로 및 우수관로 현황</h3> <h3 className="text-2xl font-medium">오수관로 및 우수관로 현황</h3>
<Button variant="outline" size="sm" className="text-white h-8 py-0 ml-auto">더보기</Button>
<Button className="h-[3.2rem]">더보기</Button>
</div> </div>
<div className="h-60 p-4"> <div className="h-60 p-4">
<div style={{ width: "100%", maxWidth: 400, height: 150 }}> <div style={{ width: "100%", maxWidth: 400, height: 150 }}>
@@ -0,0 +1,22 @@
import { PageTitle } from "@common/components";
import { useMenuStore } from "../lib/use-menu-store";
function PageLayout({ children }: { children: React.ReactNode }) {
const currentMenuInfo = useMenuStore((state) => state.currentMenuInfo);
const menuPaths = currentMenuInfo?.menuPath
?.split(">")
.map((path) => path.trim());
return (
<div className="h-auto min-h-full bg-container pb-2">
<PageTitle
title={currentMenuInfo?.menuKornNm ?? ""}
menuPaths={menuPaths ?? []}
/>
{children}
</div>
);
}
export { PageLayout };
-4
View File
@@ -10,10 +10,6 @@ function PageLayout({ children }: { children: React.ReactNode }) {
return ( return (
<div className="h-auto min-h-full bg-container pb-2"> <div className="h-auto min-h-full bg-container pb-2">
<PageTitle
title={currentMenuInfo?.menuKornNm ?? ""}
menuPaths={menuPaths ?? []}
/>
{children} {children}
</div> </div>
); );
+1 -1
View File
@@ -28,7 +28,7 @@
"chart.js": "^4.4.8", "chart.js": "^4.4.8",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "15.3.6", "next": "15.3.8",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"react-chartjs-2": "^5.3.0", "react-chartjs-2": "^5.3.0",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
+1 -1
View File
@@ -34,7 +34,7 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lucide-react": "^0.474.0", "lucide-react": "^0.474.0",
"next": "15.3.6", "next": "15.3.8",
"next-qrcode": "^2.5.1", "next-qrcode": "^2.5.1",
"next-themes": "^0.4.6", "next-themes": "^0.4.6",
"react-chartjs-2": "^5.3.0", "react-chartjs-2": "^5.3.0",
+1 -1
View File
@@ -23,7 +23,7 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lucide-react": "^0.474.0", "lucide-react": "^0.474.0",
"next": "15.3.6", "next": "15.3.8",
"react-chartjs-2": "^5.3.0", "react-chartjs-2": "^5.3.0",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
"react-dropzone": "^14.3.8", "react-dropzone": "^14.3.8",
+1 -1
View File
@@ -18,7 +18,7 @@
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"js-sha512": "^0.9.0", "js-sha512": "^0.9.0",
"lucide-react": "^0.474.0", "lucide-react": "^0.474.0",
"next": "15.3.6", "next": "15.3.8",
"react-hook-form": "^7.54.2", "react-hook-form": "^7.54.2",
"react-hot-toast": "^2.5.2", "react-hot-toast": "^2.5.2",
"tailwind-merge": "^3.0.1", "tailwind-merge": "^3.0.1",
+1 -1
View File
@@ -15,7 +15,7 @@
"@tailwindcss/vite": "^4.0.10", "@tailwindcss/vite": "^4.0.10",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"next": "15.3.6", "next": "15.3.8",
"select": "^1.1.2", "select": "^1.1.2",
"webpack": "^5.98.0", "webpack": "^5.98.0",
"zustand": "^5.0.3", "zustand": "^5.0.3",
+1 -1
View File
@@ -26,7 +26,7 @@
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"moment": "^2.30.1", "moment": "^2.30.1",
"next": "15.3.6", "next": "15.3.8",
"react-chartjs-2": "^5.3.0", "react-chartjs-2": "^5.3.0",
"react-hot-toast": "^2.5.2", "react-hot-toast": "^2.5.2",
"react-dnd": "^16.0.1", "react-dnd": "^16.0.1",
+1 -1
View File
@@ -30,7 +30,7 @@
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
"lucide-react": "^0.474.0", "lucide-react": "^0.474.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"next": "15.3.6", "next": "15.3.8",
"ol": "^7.3.0", "ol": "^7.3.0",
"ol-ext": "^4.0.11", "ol-ext": "^4.0.11",
"proj4": "^2.9.0", "proj4": "^2.9.0",
+2 -2
View File
@@ -49,5 +49,5 @@
} }
}, },
"license": "ISC", "license": "ISC",
"packageManager": "pnpm@10.25.0" "packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501"
} }
+23 -23
View File
@@ -121,8 +121,8 @@ importers:
specifier: ^0.474.0 specifier: ^0.474.0
version: 0.474.0(react@19.2.1) version: 0.474.0(react@19.2.1)
next: next:
specifier: 15.3.6 specifier: 15.3.8
version: 15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
next-qrcode: next-qrcode:
specifier: ^2.5.1 specifier: ^2.5.1
version: 2.5.1(react@19.2.1) version: 2.5.1(react@19.2.1)
@@ -251,8 +251,8 @@ importers:
specifier: ^3.0.5 specifier: ^3.0.5
version: 3.0.5 version: 3.0.5
next: next:
specifier: 15.3.6 specifier: 15.3.8
version: 15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
next-themes: next-themes:
specifier: ^0.4.6 specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 0.4.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
@@ -399,8 +399,8 @@ importers:
specifier: ^0.474.0 specifier: ^0.474.0
version: 0.474.0(react@19.2.1) version: 0.474.0(react@19.2.1)
next: next:
specifier: 15.3.6 specifier: 15.3.8
version: 15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
next-qrcode: next-qrcode:
specifier: ^2.5.1 specifier: ^2.5.1
version: 2.5.1(react@19.2.1) version: 2.5.1(react@19.2.1)
@@ -514,8 +514,8 @@ importers:
specifier: ^0.474.0 specifier: ^0.474.0
version: 0.474.0(react@19.2.1) version: 0.474.0(react@19.2.1)
next: next:
specifier: 15.3.6 specifier: 15.3.8
version: 15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
react-chartjs-2: react-chartjs-2:
specifier: ^5.3.0 specifier: ^5.3.0
version: 5.3.1(chart.js@4.5.1)(react@19.2.1) version: 5.3.1(chart.js@4.5.1)(react@19.2.1)
@@ -611,8 +611,8 @@ importers:
specifier: ^0.474.0 specifier: ^0.474.0
version: 0.474.0(react@19.2.1) version: 0.474.0(react@19.2.1)
next: next:
specifier: 15.3.6 specifier: 15.3.8
version: 15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
react-hook-form: react-hook-form:
specifier: ^7.54.2 specifier: ^7.54.2
version: 7.68.0(react@19.2.1) version: 7.68.0(react@19.2.1)
@@ -696,8 +696,8 @@ importers:
specifier: ^3.0.5 specifier: ^3.0.5
version: 3.0.5 version: 3.0.5
next: next:
specifier: 15.3.6 specifier: 15.3.8
version: 15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
ol: ol:
specifier: ^7.3.0 specifier: ^7.3.0
version: 7.5.2 version: 7.5.2
@@ -799,8 +799,8 @@ importers:
specifier: ^2.30.1 specifier: ^2.30.1
version: 2.30.1 version: 2.30.1
next: next:
specifier: 15.3.6 specifier: 15.3.8
version: 15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
ol: ol:
specifier: ^7.3.0 specifier: ^7.3.0
version: 7.5.2 version: 7.5.2
@@ -941,8 +941,8 @@ importers:
specifier: ^2.30.1 specifier: ^2.30.1
version: 2.30.1 version: 2.30.1
next: next:
specifier: 15.3.6 specifier: 15.3.8
version: 15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1) version: 15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1)
ol: ol:
specifier: ^7.3.0 specifier: ^7.3.0
version: 7.5.2 version: 7.5.2
@@ -2341,8 +2341,8 @@ packages:
'@napi-rs/wasm-runtime@0.2.12': '@napi-rs/wasm-runtime@0.2.12':
resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==}
'@next/env@15.3.6': '@next/env@15.3.8':
resolution: {integrity: sha512-/cK+QPcfRbDZxmI/uckT4lu9pHCfRIPBLqy88MhE+7Vg5hKrEYc333Ae76dn/cw2FBP2bR/GoK/4DU+U7by/Nw==} resolution: {integrity: sha512-SAfHg0g91MQVMPioeFeDjE+8UPF3j3BvHjs8ZKJAUz1BG7eMPvfCKOAgNWJ6s1MLNeP6O2InKQRTNblxPWuq+Q==}
'@next/eslint-plugin-next@15.1.7': '@next/eslint-plugin-next@15.1.7':
resolution: {integrity: sha512-kRP7RjSxfTO13NE317ek3mSGzoZlI33nc/i5hs1KaWpK+egs85xg0DJ4p32QEiHnR0mVjuUfhRIun7awqfL7pQ==} resolution: {integrity: sha512-kRP7RjSxfTO13NE317ek3mSGzoZlI33nc/i5hs1KaWpK+egs85xg0DJ4p32QEiHnR0mVjuUfhRIun7awqfL7pQ==}
@@ -5478,8 +5478,8 @@ packages:
react: ^19.2.1 react: ^19.2.1
react-dom: ^19.2.1 react-dom: ^19.2.1
next@15.3.6: next@15.3.8:
resolution: {integrity: sha512-oI6D1zbbsh6JzzZFDCSHnnx6Qpvd1fSkVJu/5d8uluqnxzuoqtodVZjYvNovooznUq8udSAiKp7MbwlfZ8Gm6w==} resolution: {integrity: sha512-L+4c5Hlr84fuaNADZbB9+ceRX9/CzwxJ+obXIGHupboB/Q1OLbSUapFs4bO8hnS/E6zV/JDX7sG1QpKVR2bguA==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@@ -7660,7 +7660,7 @@ snapshots:
'@tybys/wasm-util': 0.10.1 '@tybys/wasm-util': 0.10.1
optional: true optional: true
'@next/env@15.3.6': {} '@next/env@15.3.8': {}
'@next/eslint-plugin-next@15.1.7': '@next/eslint-plugin-next@15.1.7':
dependencies: dependencies:
@@ -11250,9 +11250,9 @@ snapshots:
react: 19.2.1 react: 19.2.1
react-dom: 19.2.1(react@19.2.1) react-dom: 19.2.1(react@19.2.1)
next@15.3.6(react-dom@19.2.1(react@19.2.1))(react@19.2.1): next@15.3.8(react-dom@19.2.1(react@19.2.1))(react@19.2.1):
dependencies: dependencies:
'@next/env': 15.3.6 '@next/env': 15.3.8
'@swc/counter': 0.1.3 '@swc/counter': 0.1.3
'@swc/helpers': 0.5.15 '@swc/helpers': 0.5.15
busboy: 1.6.0 busboy: 1.6.0