Merge branch 'main' into iipbs/sn/dev

This commit is contained in:
ljpark
2025-12-11 18:09:38 +09:00
20 changed files with 8121 additions and 6929 deletions
+9 -9
View File
@@ -25,7 +25,7 @@
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8",
"@tanstack/react-query": "^5.67.1",
"@tanstack/react-query": "^5.75.5",
"@tanstack/react-query-devtools": "^5.75.5",
"@tanstack/react-table": "^8.21.2",
"@tinymce/tinymce-react": "^5.1.1",
@@ -34,7 +34,7 @@
"dayjs": "^1.11.13",
"js-cookie": "^3.0.5",
"lucide-react": "^0.474.0",
"next": "15.3.0",
"next": "15.3.6",
"next-qrcode": "^2.5.1",
"next-themes": "^0.4.6",
"react-chartjs-2": "^5.3.0",
@@ -47,17 +47,17 @@
"zustand": "^5.0.3"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@eslint/eslintrc": "^3.0.0",
"@types/js-cookie": "^3.0.6",
"@types/node": "^22.13.1",
"@types/webpack": "^5.28.5",
"eslint": "^9",
"eslint-config-next": "15.1.7",
"postcss": "^8",
"eslint": "^9.0.0",
"eslint-config-next": "15.4.0",
"postcss": "^8.4.49",
"prettier": "^3.4.2",
"prettier-plugin-tailwindcss": "^0.6.11",
"steiger": "^0.5.5",
"tailwindcss": "^3.4.1",
"typescript": "^5"
"tailwindcss": "^3.4.14",
"typescript": "^5.7.2"
}
}
}
+15 -14
View File
@@ -1,3 +1,4 @@
import React from "react";
import { type UseQueryResult } from "@tanstack/react-query";
import type { PageableList } from "../model";
@@ -9,24 +10,24 @@ import type { PageableList } from "../model";
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
options: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Empty?: JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Empty?: React.ReactElement;
Success: (
data: UseQueryResult<PageableList<T>> & {
data: NonNullable<UseQueryResult<T>["data"]>;
},
) => JSX.Element;
) => React.ReactElement;
},
): JSX.Element;
): React.ReactElement;
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
options: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Success: (data: UseQueryResult<PageableList<T>>) => JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Success: (data: UseQueryResult<PageableList<T>>) => React.ReactElement;
},
): JSX.Element;
): React.ReactElement;
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
{
@@ -35,12 +36,12 @@ export function matchQueryStatus<T>(
Empty,
Success,
}: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Empty?: JSX.Element;
Success: (data: UseQueryResult<PageableList<T>>) => JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Empty?: React.ReactElement;
Success: (data: UseQueryResult<PageableList<T>>) => React.ReactElement;
},
): JSX.Element {
): React.ReactElement {
if (query.isLoading && Loading) {
return Loading;
}
+1 -1
View File
@@ -28,7 +28,7 @@
"chart.js": "^4.4.8",
"dayjs": "^1.11.13",
"js-cookie": "^3.0.5",
"next": "15.3.0",
"next": "15.3.6",
"next-themes": "^0.4.6",
"react-chartjs-2": "^5.3.0",
"react-dnd": "^16.0.1",
+9 -9
View File
@@ -25,7 +25,7 @@
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-tooltip": "^1.1.8",
"@tanstack/react-query": "^5.67.1",
"@tanstack/react-query": "^5.75.5",
"@tanstack/react-query-devtools": "^5.75.5",
"@tanstack/react-table": "^8.21.2",
"@tinymce/tinymce-react": "^5.1.1",
@@ -34,7 +34,7 @@
"dayjs": "^1.11.13",
"js-cookie": "^3.0.5",
"lucide-react": "^0.474.0",
"next": "15.3.0",
"next": "15.3.6",
"next-qrcode": "^2.5.1",
"next-themes": "^0.4.6",
"react-chartjs-2": "^5.3.0",
@@ -47,17 +47,17 @@
"zustand": "^5.0.3"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@eslint/eslintrc": "^3.0.0",
"@types/js-cookie": "^3.0.6",
"@types/node": "^22.13.1",
"@types/webpack": "^5.28.5",
"eslint": "^9",
"eslint-config-next": "15.1.7",
"postcss": "^8",
"eslint": "^9.0.0",
"eslint-config-next": "15.4.0",
"postcss": "^8.4.49",
"prettier": "^3.4.2",
"prettier-plugin-tailwindcss": "^0.6.11",
"steiger": "^0.5.5",
"tailwindcss": "^3.4.1",
"typescript": "^5"
"tailwindcss": "^3.4.14",
"typescript": "^5.7.2"
}
}
}
+14 -3
View File
@@ -32,11 +32,22 @@ export class LoginApiService implements LoginService {
});
const data = await response.json();
console.log('data ', data)
const accessToken = data[ACCESS_TOKEN];
const tokenId = data[AUTH_USER_ID];
if (!accessToken || !tokenId) {
throw new Error("Missing required authentication tokens");
if (data.message == 'Invalid Credentials' ) {
throw new Error('아이디와 비밀번호가 일치하지 않습니다.');
} else if (data.message == 'User not found') {
throw new Error('존재하지 않는 아이디입니다.');
} else if (data.message == 'User is not active') {
throw new Error('활성화되지 않은 계정입니다.');
} else if (data.message == 'User is not verified') {
throw new Error('이메일 인증이 필요합니다.');
} else {
throw new Error(data.message);
}
}
tokenManager.setToken(CLAIM_NAME, accessToken);
@@ -47,9 +58,9 @@ export class LoginApiService implements LoginService {
);
} catch (error) {
if (error instanceof AxiosError) {
throw new Error(`Login failed: ${error.response?.data?.message}`);
throw new Error(`Login 실패 ${error.response?.data?.message}`);
}
throw new Error(`Login failed: ${error}`);
throw new Error(`Login 실패 ${error}`);
}
}
@@ -6,7 +6,8 @@ export const editorBaseConfig = {
// 자체 호스팅 모드 설정 - GPL 라이선스
licenseKey: "gpl",
init: {
language: "ko-KR",
language: "ko_KR",
language_url: '/tinymce/langs/ko_KR.js', // 직접 호스팅한 경우 경로 지정
height: 500,
// 폐쇄망 환경을 위한 설정
base_url: "/tinymce",
+17 -2
View File
@@ -1,20 +1,30 @@
"use client";
import { useState } from "react";
import Image from "next/image";
import { images } from "@common/assets";
import { LoginApi } from "@/entities/auth";
import "./login.css";
function LoginPage() {
const [errorMessage, setErrorMessage] = useState<string>("");
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setErrorMessage(""); // 에러 메시지 초기화
const formData = new FormData(e.target as HTMLFormElement);
const userId = formData.get("id") as string;
const password = formData.get("password") as string;
await LoginApi.login({ userId, password });
window.location.href = "/dashboard";
try {
await LoginApi.login({ userId, password });
window.location.href = "/dashboard";
} catch (error) {
const message =
error instanceof Error ? error.message : "로그인에 실패했습니다.";
setErrorMessage(message);
}
};
return (
@@ -81,6 +91,11 @@ function LoginPage() {
</div>
{/* <a href="javascript:fnUserSearch();" className=" pw_message fx"><i className="xi-external-link"></i>비밀번호 또는 아이디를 잃어버리셨나요?</a> */}
</div>
{errorMessage && (
<div className="error_message">
<span>{errorMessage}</span>
</div>
)}
<button type="submit" className="login_btn fx">
<span>LOGIN</span>
</button>
+14
View File
@@ -118,6 +118,20 @@ body {
color: #327af5;
font-size: 20px;
}
.login .login_box .error_message {
margin: 20px 0;
padding: 12px 20px;
background: #fee;
border: 1px solid #fcc;
border-radius: 5px;
color: #c33;
font-size: 14px;
text-align: center;
}
.login .login_box .error_message span {
display: block;
font-weight: 500;
}
.login .login_box .login_btn {
position: relative;
border-radius: 5px;
+15 -14
View File
@@ -1,3 +1,4 @@
import type React from "react";
import { type UseQueryResult } from "@tanstack/react-query";
import type { PageableList } from "../model";
@@ -9,24 +10,24 @@ import type { PageableList } from "../model";
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
options: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Empty?: JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Empty?: React.ReactElement;
Success: (
data: UseQueryResult<PageableList<T>> & {
data: NonNullable<UseQueryResult<T>["data"]>;
},
) => JSX.Element;
) => React.ReactElement;
},
): JSX.Element;
): React.ReactElement;
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
options: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Success: (data: UseQueryResult<PageableList<T>>) => JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Success: (data: UseQueryResult<PageableList<T>>) => React.ReactElement;
},
): JSX.Element;
): React.ReactElement;
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
{
@@ -35,12 +36,12 @@ export function matchQueryStatus<T>(
Empty,
Success,
}: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Empty?: JSX.Element;
Success: (data: UseQueryResult<PageableList<T>>) => JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Empty?: React.ReactElement;
Success: (data: UseQueryResult<PageableList<T>>) => React.ReactElement;
},
): JSX.Element {
): React.ReactElement {
if (query.isLoading && Loading) {
return Loading;
}
+8 -8
View File
@@ -16,14 +16,14 @@
"@minoru/react-dnd-treeview": "^3.5.0",
"@radix-ui/react-label": "^2.1.2",
"@radix-ui/react-slot": "^1.1.2",
"@tanstack/react-query": "^5.67.1",
"@tanstack/react-query": "^5.75.5",
"@tanstack/react-table": "^8.21.2",
"axios": "^1.8.1",
"chart.js": "^4.4.8",
"dayjs": "^1.11.13",
"js-cookie": "^3.0.5",
"lucide-react": "^0.474.0",
"next": "15.2.3",
"next": "15.3.6",
"react-chartjs-2": "^5.3.0",
"react-dnd": "^16.0.1",
"react-dropzone": "^14.3.8",
@@ -34,18 +34,18 @@
"zustand": "^5.0.3"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
"@eslint/eslintrc": "^3.0.0",
"@faker-js/faker": "^9.5.0",
"@types/js-cookie": "^3.0.6",
"@types/node": "^22.17.0",
"@types/webpack": "^5.28.5",
"eslint": "^9",
"eslint-config-next": "15.2.3",
"postcss": "^8",
"eslint": "^9.0.0",
"eslint-config-next": "15.4.0",
"postcss": "^8.4.49",
"prettier": "^3.4.2",
"prettier-plugin-tailwindcss": "^0.6.11",
"steiger": "^0.5.5",
"tailwindcss": "^3.4.1",
"typescript": "^5"
"tailwindcss": "^3.4.14",
"typescript": "^5.7.2"
}
}
@@ -1,6 +1,6 @@
"use client";
import { useState, useEffect, useRef } from "react";
import React, { useState, useEffect, useRef } from "react";
import { PageLayout } from "@/shared/ui/page-layout";
import { Button } from "@common/components";
import {
@@ -233,7 +233,7 @@ function DataInsertPage() {
};
// 단순 트리 컴포넌트 (펼침/접기 지원)
function SimpleTree({ nodes, selectedId, onSelect, depth = 0 }: { nodes: any[]; selectedId: string; onSelect: (node: any) => void; depth?: number }): JSX.Element {
function SimpleTree({ nodes, selectedId, onSelect, depth = 0 }: { nodes: any[]; selectedId: string; onSelect: (node: any) => void; depth?: number }): React.ReactElement {
return (
<ul
className="list-none p-0 m-0"
+15 -14
View File
@@ -1,3 +1,4 @@
import React from "react";
import { type UseQueryResult } from "@tanstack/react-query";
import type { PageableList } from "../model";
@@ -9,24 +10,24 @@ import type { PageableList } from "../model";
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
options: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Empty?: JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Empty?: React.ReactElement;
Success: (
data: UseQueryResult<PageableList<T>> & {
data: NonNullable<UseQueryResult<T>["data"]>;
},
) => JSX.Element;
) => React.ReactElement;
},
): JSX.Element;
): React.ReactElement;
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
options: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Success: (data: UseQueryResult<PageableList<T>>) => JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Success: (data: UseQueryResult<PageableList<T>>) => React.ReactElement;
},
): JSX.Element;
): React.ReactElement;
export function matchQueryStatus<T>(
query: UseQueryResult<PageableList<T>>,
{
@@ -35,12 +36,12 @@ export function matchQueryStatus<T>(
Empty,
Success,
}: {
Loading?: JSX.Element;
Errored?: JSX.Element | ((error: unknown) => JSX.Element);
Empty?: JSX.Element;
Success: (data: UseQueryResult<PageableList<T>>) => JSX.Element;
Loading?: React.ReactElement;
Errored?: React.ReactElement | ((error: unknown) => React.ReactElement);
Empty?: React.ReactElement;
Success: (data: UseQueryResult<PageableList<T>>) => React.ReactElement;
},
): JSX.Element {
): React.ReactElement {
if (query.isLoading && Loading) {
return Loading;
}
@@ -34,7 +34,7 @@ export interface SdmInfoRegFormProps {
type FieldComponent = (
field: ControllerRenderProps<SdmInfoFormData, keyof SdmInfoFormData>
) => JSX.Element;
) => React.ReactElement<{ disabled?: boolean }>;
export function SdmInfoRegForm({
form,
@@ -4,7 +4,7 @@ import type { DemandCompType } from "@common/business_components/ui/sdmInsertFor
import { Button, Input } from "@common/components";
import { zodResolver } from "@hookform/resolvers/zod";
import { sha512 } from 'js-sha512';
import { useEffect, useMemo, useState } from "react";
import React, { useEffect, useMemo, useState } from "react";
import { FormProvider, useForm, type ControllerRenderProps } from "react-hook-form";
import toast from "react-hot-toast";
import * as z from "zod";
@@ -47,7 +47,7 @@ export function SdmLoginForm() {
}), [isBznmTotNoDisabled]);
type SdmLoginForm = z.infer<typeof sdmLoginFormSchema>;
type FieldComponent = (field: ControllerRenderProps<SdmLoginForm, keyof SdmLoginForm>) => JSX.Element;
type FieldComponent = (field: ControllerRenderProps<SdmLoginForm, keyof SdmLoginForm>) => React.ReactElement;
const formSchema = sdmLoginFormSchema;
+2 -4
View File
@@ -7,9 +7,7 @@ import { type FoStore, StoreZus } from './store'
export type StoreApi = ReturnType<typeof StoreZus>
export const StoreContext = createContext<StoreApi | undefined>(
undefined,
)
export const StoreContext = createContext<StoreApi | null>(null);
export interface StoreProviderProps {
children: ReactNode
@@ -18,7 +16,7 @@ export interface StoreProviderProps {
export const StoreProvider = ({
children,
}: StoreProviderProps) => {
const storeRef = useRef<StoreApi>()
const storeRef = useRef<StoreApi | null>(null);
if (!storeRef.current) {
const store = StoreZus()
+13 -11
View File
@@ -12,6 +12,8 @@
"build": "turbo run build",
"build:common": "turbo run build --filter=@common/*",
"dev": "turbo run dev",
"build:cm": "turbo run build --filter=cm",
"build:cs": "turbo run build --filter=cs",
"build:sn": "turbo run build --filter=sn",
"build:wr": "turbo run build --filter=wr",
"build:fo": "turbo run build --filter=fo",
@@ -27,25 +29,25 @@
},
"dependencies": {
"chart.js": "^4.4.8",
"react": "^18.3.1",
"react": "^19.2.1",
"react-chartjs-2": "^5.3.0",
"react-dom": "^18.3.1",
"react-dom": "^19.2.1",
"zustand": "^5.0.3"
},
"devDependencies": {
"@types/node": "^22.13.9",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"@types/node": "^22.13.1",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"turbo": "2.4.2"
},
"pnpm": {
"overrides": {
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"react": "^19.2.1",
"react-dom": "^19.2.1"
}
},
"license": "ISC",
"packageManager": "pnpm@8.15.5+sha1.a58c038faac410c947dbdb93eb30994037d0fce2"
}
"packageManager": "pnpm@9.12.3"
}
@@ -17,7 +17,7 @@
```json
"dependencies": {
"@common/business_components": "workspace:*",
"next": "15.1.7"
"next": "15.3.6"
},
```
@@ -77,7 +77,7 @@ interface SdmRegFormProps {
type FieldComponent = (
field: ControllerRenderProps<FormSchema, keyof FormSchema>,
) => JSX.Element;
) => React.ReactElement;
export function SdmRegForm({
form,
@@ -704,7 +704,7 @@ export function SdmRegForm({
{isRequired && <span className="ml-1 text-red-500">*</span>}
</label>
{React.cloneElement(component(field), {
{React.cloneElement(component(field) as React.ReactElement<any>, {
id: inputId,
"aria-required": isRequired,
"aria-invalid": !!error,
+2 -1
View File
@@ -1,4 +1,5 @@
declare module "*.mdx" {
let MDXComponent: (props: unknown) => JSX.Element;
import type React from "react";
let MDXComponent: (props: unknown) => React.ReactElement;
export default MDXComponent;
}
+7977 -6830
View File
File diff suppressed because it is too large Load Diff