diff --git a/docker/dev/docker-compose.invyone.yml b/docker/dev/docker-compose.invyone.yml
index d76e6730..591573fa 100644
--- a/docker/dev/docker-compose.invyone.yml
+++ b/docker/dev/docker-compose.invyone.yml
@@ -36,7 +36,7 @@ services:
# JWT_SECRET 은 docker/dev/.env 에서 주입 (이 파일은 git 추적, .env 는 gitignored + syncthing 동기화)
JWT_SECRET: ${JWT_SECRET:?JWT_SECRET 환경변수 필요. docker/dev/.env 파일 확인}
JWT_EXPIRATION: ${JWT_EXPIRATION:-86400000}
- CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-http://localhost:3000,http://localhost:9772,http://100.126.230.80:9772,http://*.invyone.com:[*],https://*.invyone.com:[*],http://*.invyone.com,https://*.invyone.com}
+ CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-http://localhost:3000,http://localhost:9772,http://100.126.230.80:9772,http://*.invyone.com:[*],https://*.invyone.com:[*],http://*.invyone.com,https://*.invyone.com,http://*.nip.io:[*],http://*.sslip.io:[*]}
FILE_UPLOAD_DIR: ./uploads
volumes:
- ../../backend-spring:/app
diff --git a/frontend/app/(auth)/login/page.tsx b/frontend/app/(auth)/login/page.tsx
index ef0b039a..af23073b 100644
--- a/frontend/app/(auth)/login/page.tsx
+++ b/frontend/app/(auth)/login/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import { useEffect, useRef, useCallback } from "react";
+import { useEffect, useRef, useCallback, useState } from "react";
import { useTheme } from "next-themes";
import { useLogin } from "@/hooks/useLogin";
import { animatedThemeChange } from "@/lib/themeTransition";
@@ -28,6 +28,12 @@ export default function LoginPage() {
const { theme, setTheme: setNextTheme, resolvedTheme } = useTheme();
const isDark = (resolvedTheme ?? theme) === "dark";
+ // SSR 시점엔 theme 가 undefined 라 SSR HTML 과 클라 첫 렌더의 className 이 달라
+ // hydration mismatch 가 남. mounted 가드로 첫 렌더는 SSR 과 동일하게 그리고
+ // mount 후에만 isDark 반영.
+ const [mounted, setMounted] = useState(false);
+ useEffect(() => setMounted(true), []);
+
// resolvedTheme 가 바뀌면 .inv-login 에 dark 클래스 동기화 (login.css 가 .inv-login.dark 셀렉터로 작성됨)
useEffect(() => {
const root = rootRef.current;
@@ -117,8 +123,8 @@ export default function LoginPage() {
-
-
+
+
diff --git a/frontend/components/dash/CardMiniView.tsx b/frontend/components/dash/CardMiniView.tsx
deleted file mode 100644
index dadc1541..00000000
--- a/frontend/components/dash/CardMiniView.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-'use client';
-
-interface CardMiniViewProps {
- templateName: string;
- category?: string;
- tableName?: string;
-}
-
-export function CardMiniView({ templateName, category, tableName }: CardMiniViewProps) {
- return (
-
-
-
- {category && (
-
- )}
- {tableName && (
-
- )}
-
-
- );
-}
diff --git a/frontend/components/dash/CreateDashboardModal.tsx b/frontend/components/dash/CreateDashboardModal.tsx
index 04127361..118a6b97 100644
--- a/frontend/components/dash/CreateDashboardModal.tsx
+++ b/frontend/components/dash/CreateDashboardModal.tsx
@@ -8,8 +8,11 @@ interface CreateDashboardModalProps {
open: boolean;
onClose: () => void;
onSubmit: (payload: { name: string; icon: string; is_personal: boolean }) => Promise
| void;
+ /** 'create' (기본) 는 새 대시보드 생성, 'edit' 은 기존 항목 수정 — 제목/버튼/공유범위 분기 */
+ mode?: 'create' | 'edit';
defaultName?: string;
defaultIcon?: string;
+ defaultIsPersonal?: boolean;
submitting?: boolean;
}
@@ -24,23 +27,26 @@ export function CreateDashboardModal({
open,
onClose,
onSubmit,
+ mode = 'create',
defaultName = '',
defaultIcon = 'ClipboardList',
+ defaultIsPersonal = false,
submitting = false,
}: CreateDashboardModalProps) {
+ const isEdit = mode === 'edit';
const [name, setName] = useState(defaultName);
const [icon, setIcon] = useState(defaultIcon);
- const [isPersonal, setIsPersonal] = useState(false);
+ const [isPersonal, setIsPersonal] = useState(defaultIsPersonal);
const nameRef = useRef(null);
useEffect(() => {
if (open) {
setName(defaultName);
setIcon(defaultIcon);
- setIsPersonal(false);
+ setIsPersonal(defaultIsPersonal);
setTimeout(() => nameRef.current?.focus(), 30);
}
- }, [open, defaultName, defaultIcon]);
+ }, [open, defaultName, defaultIcon, defaultIsPersonal]);
if (!open) return null;
@@ -58,7 +64,9 @@ export function CreateDashboardModal({
>
-
새 대시보드 만들기
+
+ {isEdit ? '대시보드 수정' : '새 대시보드 만들기'}
+