@restnfeel/agentc-starter-kit
Version:
한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템
388 lines (385 loc) • 14.4 kB
JavaScript
"use client";
import { jsx } from 'react/jsx-runtime';
import { useReducer, useCallback, useEffect, createContext, useContext } from 'react';
const initialModalState = {
isOpen: false,
isMinimized: false,
position: { x: 0, y: 0 },
size: { width: "800px", height: "600px" },
zIndex: 1000,
};
const initialState = {
modalState: initialModalState,
currentSession: null,
sessions: [],
nextZIndex: 1000,
};
const STORAGE_KEY = "desktop-chat-modal-state";
const SESSIONS_STORAGE_KEY = "desktop-chat-sessions";
function modalStateReducer(state, action) {
var _a, _b;
switch (action.type) {
case "OPEN_MODAL":
return {
...state,
modalState: {
...state.modalState,
isOpen: true,
zIndex: state.nextZIndex,
},
nextZIndex: state.nextZIndex + 1,
};
case "CLOSE_MODAL":
return {
...state,
modalState: {
...state.modalState,
isOpen: false,
isMinimized: false,
},
};
case "MINIMIZE_MODAL":
return {
...state,
modalState: {
...state.modalState,
isMinimized: true,
},
};
case "MAXIMIZE_MODAL":
return {
...state,
modalState: {
...state.modalState,
isMinimized: false,
},
};
case "SET_POSITION":
return {
...state,
modalState: {
...state.modalState,
position: action.payload,
},
};
case "SET_SIZE":
return {
...state,
modalState: {
...state.modalState,
size: action.payload,
},
};
case "BRING_TO_FRONT":
return {
...state,
modalState: {
...state.modalState,
zIndex: state.nextZIndex,
},
nextZIndex: state.nextZIndex + 1,
};
case "CREATE_SESSION": {
const newSession = {
id: action.payload.id,
title: action.payload.title || `Chat ${state.sessions.length + 1}`,
messages: [],
createdAt: new Date(),
lastActivity: new Date(),
};
return {
...state,
sessions: [...state.sessions, newSession],
currentSession: newSession,
};
}
case "SWITCH_SESSION": {
const session = state.sessions.find((s) => s.id === action.payload);
return {
...state,
currentSession: session || null,
};
}
case "DELETE_SESSION": {
const filteredSessions = state.sessions.filter((s) => s.id !== action.payload);
const wasCurrentSession = ((_a = state.currentSession) === null || _a === void 0 ? void 0 : _a.id) === action.payload;
return {
...state,
sessions: filteredSessions,
currentSession: wasCurrentSession
? filteredSessions[0] || null
: state.currentSession,
};
}
case "ADD_MESSAGE": {
if (!state.currentSession)
return state;
const updatedSessions = state.sessions.map((session) => session.id === state.currentSession.id
? {
...session,
messages: [...session.messages, action.payload],
lastActivity: new Date(),
}
: session);
const updatedCurrentSession = {
...state.currentSession,
messages: [...state.currentSession.messages, action.payload],
lastActivity: new Date(),
};
return {
...state,
sessions: updatedSessions,
currentSession: updatedCurrentSession,
};
}
case "CLEAR_CURRENT_SESSION": {
if (!state.currentSession)
return state;
const updatedSessions = state.sessions.map((session) => session.id === state.currentSession.id
? {
...session,
messages: [],
lastActivity: new Date(),
}
: session);
const updatedCurrentSession = {
...state.currentSession,
messages: [],
lastActivity: new Date(),
};
return {
...state,
sessions: updatedSessions,
currentSession: updatedCurrentSession,
};
}
case "SET_SESSIONS":
return {
...state,
sessions: action.payload,
currentSession: action.payload[0] || null,
};
case "UPDATE_SESSION_ACTIVITY": {
const updatedSessions = state.sessions.map((session) => session.id === action.payload
? { ...session, lastActivity: new Date() }
: session);
const updatedCurrentSession = ((_b = state.currentSession) === null || _b === void 0 ? void 0 : _b.id) === action.payload
? { ...state.currentSession, lastActivity: new Date() }
: state.currentSession;
return {
...state,
sessions: updatedSessions,
currentSession: updatedCurrentSession,
};
}
default:
return state;
}
}
const ModalStateContext = createContext(undefined);
function useModalState() {
const context = useContext(ModalStateContext);
if (!context) {
throw new Error("useModalState must be used within a ModalStateProvider");
}
return context;
}
function ModalStateProvider({ children, persistToStorage = true, maxSessions = 10, sessionTimeout = 24 * 60 * 60 * 1000, // 24 hours
}) {
const [state, dispatch] = useReducer(modalStateReducer, initialState);
// Generate unique session ID
const generateSessionId = useCallback(() => {
return `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}, []);
// Generate unique message ID
const generateMessageId = useCallback(() => {
return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}, []);
// Modal actions
const openModal = useCallback(() => {
dispatch({ type: "OPEN_MODAL" });
}, []);
const closeModal = useCallback(() => {
dispatch({ type: "CLOSE_MODAL" });
}, []);
const minimizeModal = useCallback(() => {
dispatch({ type: "MINIMIZE_MODAL" });
}, []);
const maximizeModal = useCallback(() => {
dispatch({ type: "MAXIMIZE_MODAL" });
}, []);
const setModalPosition = useCallback((x, y) => {
dispatch({ type: "SET_POSITION", payload: { x, y } });
}, []);
const setModalSize = useCallback((width, height) => {
dispatch({ type: "SET_SIZE", payload: { width, height } });
}, []);
const bringToFront = useCallback(() => {
dispatch({ type: "BRING_TO_FRONT" });
}, []);
// Chat session actions
const createSession = useCallback((title) => {
const sessionId = generateSessionId();
dispatch({ type: "CREATE_SESSION", payload: { id: sessionId, title } });
return sessionId;
}, [generateSessionId]);
const switchSession = useCallback((sessionId) => {
dispatch({ type: "SWITCH_SESSION", payload: sessionId });
dispatch({ type: "UPDATE_SESSION_ACTIVITY", payload: sessionId });
}, []);
const deleteSession = useCallback((sessionId) => {
dispatch({ type: "DELETE_SESSION", payload: sessionId });
}, []);
const addMessage = useCallback((messageData) => {
const message = {
...messageData,
id: generateMessageId(),
timestamp: new Date(),
};
dispatch({ type: "ADD_MESSAGE", payload: message });
}, [generateMessageId]);
const clearCurrentSession = useCallback(() => {
dispatch({ type: "CLEAR_CURRENT_SESSION" });
}, []);
// Storage functions
const saveToStorage = useCallback(() => {
if (!persistToStorage || typeof window === "undefined")
return;
try {
// Save modal state
const modalStateToSave = {
position: state.modalState.position,
size: state.modalState.size,
isMinimized: state.modalState.isMinimized,
};
localStorage.setItem(STORAGE_KEY, JSON.stringify(modalStateToSave));
// Save sessions (with date serialization)
const sessionsToSave = state.sessions.map((session) => ({
...session,
createdAt: session.createdAt.toISOString(),
lastActivity: session.lastActivity.toISOString(),
messages: session.messages.map((msg) => ({
...msg,
timestamp: msg.timestamp.toISOString(),
})),
}));
localStorage.setItem(SESSIONS_STORAGE_KEY, JSON.stringify(sessionsToSave));
}
catch (error) {
console.warn("Failed to save modal state to storage:", error);
}
}, [state, persistToStorage]);
const loadFromStorage = useCallback(() => {
if (!persistToStorage || typeof window === "undefined")
return;
try {
// Load modal state
const savedModalState = localStorage.getItem(STORAGE_KEY);
if (savedModalState) {
const parsed = JSON.parse(savedModalState);
if (parsed.position) {
dispatch({ type: "SET_POSITION", payload: parsed.position });
}
if (parsed.size) {
dispatch({ type: "SET_SIZE", payload: parsed.size });
}
if (parsed.isMinimized) {
dispatch({ type: "MINIMIZE_MODAL" });
}
}
// Load sessions
const savedSessions = localStorage.getItem(SESSIONS_STORAGE_KEY);
if (savedSessions) {
const parsed = JSON.parse(savedSessions);
const now = new Date();
// Filter out expired sessions and restore dates
const validSessions = parsed
.map((session) => ({
...session,
createdAt: new Date(session.createdAt),
lastActivity: new Date(session.lastActivity),
messages: session.messages.map((msg) => ({
...msg,
timestamp: new Date(msg.timestamp),
})),
}))
.filter((session) => {
const timeSinceActivity = now.getTime() - session.lastActivity.getTime();
return timeSinceActivity < sessionTimeout;
})
.slice(-maxSessions); // Keep only the most recent sessions
if (validSessions.length > 0) {
dispatch({ type: "SET_SESSIONS", payload: validSessions });
}
}
}
catch (error) {
console.warn("Failed to load modal state from storage:", error);
}
}, [persistToStorage, sessionTimeout, maxSessions]);
const clearStorage = useCallback(() => {
if (typeof window === "undefined")
return;
try {
localStorage.removeItem(STORAGE_KEY);
localStorage.removeItem(SESSIONS_STORAGE_KEY);
}
catch (error) {
console.warn("Failed to clear modal state storage:", error);
}
}, []);
// Auto-save to storage when state changes
useEffect(() => {
if (persistToStorage) {
const timeoutId = setTimeout(saveToStorage, 500); // Debounce saves
return () => clearTimeout(timeoutId);
}
}, [state, saveToStorage, persistToStorage]);
// Load from storage on mount
useEffect(() => {
loadFromStorage();
}, [loadFromStorage]);
// Create initial session if none exists
useEffect(() => {
if (state.sessions.length === 0 && !state.currentSession) {
createSession("Welcome Chat");
}
}, [state.sessions.length, state.currentSession, createSession]);
// Cleanup expired sessions periodically
useEffect(() => {
const cleanupInterval = setInterval(() => {
const now = new Date();
const validSessions = state.sessions.filter((session) => {
const timeSinceActivity = now.getTime() - session.lastActivity.getTime();
return timeSinceActivity < sessionTimeout;
});
if (validSessions.length !== state.sessions.length) {
dispatch({ type: "SET_SESSIONS", payload: validSessions });
}
}, 60000); // Check every minute
return () => clearInterval(cleanupInterval);
}, [state.sessions, sessionTimeout]);
const contextValue = {
modalState: state.modalState,
openModal,
closeModal,
minimizeModal,
maximizeModal,
setModalPosition,
setModalSize,
bringToFront,
currentSession: state.currentSession,
sessions: state.sessions,
createSession,
switchSession,
deleteSession,
addMessage,
clearCurrentSession,
saveToStorage,
loadFromStorage,
clearStorage,
};
return (jsx(ModalStateContext.Provider, { value: contextValue, children: children }));
}
export { ModalStateProvider, ModalStateProvider as default, useModalState };
//# sourceMappingURL=modal-state-context.js.map