import { useMemo } from "react"; import { AppShell } from "./components/AppShell"; import { QOutlook } from "./features/qoutlook/QOutlook"; import { QPowerPoint } from "./features/qpowerpoint/QPowerPoint"; import { QWord } from "./features/qword/QWord"; import { QExcell } from "./features/qexcell/QExcell"; import { initialState } from "./data/sampleData"; import { usePersistentState } from "./hooks/usePersistentState"; import type { AppId, MailMessage, QOfficeState, SlideDeck, WordDocument, Workbook } from "./types"; const STORAGE_KEY = "qoffice-state-v1"; function migrateQOfficeState(state: QOfficeState): QOfficeState { const launchChecklistAttachments = initialState.mail.messages.find((message) => message.id === "mail-1")?.attachments; const sampleSheet = initialState.workbook.sheets.find((sheet) => sheet.id === "sheet-1"); const sampleSlidesById = Object.fromEntries(initialState.deck.slides.map((slide) => [slide.id, slide])); const sampleWordHtml = initialState.word.html; const needsSampleWordColor = state.word.id === initialState.word.id && sampleWordHtml.includes("Ключевой результат") && !state.word.html.includes("Ключевой результат"); let changed = false; if (needsSampleWordColor) { changed = true; } const messages = state.mail.messages.map((message) => { if (!launchChecklistAttachments || message.id !== "mail-1" || (message.attachments?.length ?? 0) > 0) { return message; } changed = true; return { ...message, attachments: launchChecklistAttachments }; }); const sheets = state.workbook.id === initialState.workbook.id && sampleSheet ? state.workbook.sheets.map((sheet) => { if (sheet.id !== "sheet-1") { return sheet; } const needsMergedCells = (sheet.mergedCells?.length ?? 0) === 0; const needsSampleCell = !sheet.cells.A8 && sampleSheet.cells.A8; const missingSampleFormats = Object.entries(sampleSheet.cellFormats ?? {}).filter(([address]) => !sheet.cellFormats?.[address]); const missingSampleCharts = (sampleSheet.charts ?? []).filter((chart) => !(sheet.charts ?? []).some((existingChart) => existingChart.id === chart.id)); if (!needsMergedCells && !needsSampleCell && missingSampleFormats.length === 0 && missingSampleCharts.length === 0) { return sheet; } changed = true; return { ...sheet, cells: needsSampleCell ? { ...sheet.cells, A8: sampleSheet.cells.A8 } : sheet.cells, mergedCells: needsMergedCells ? sampleSheet.mergedCells : sheet.mergedCells, cellFormats: missingSampleFormats.length > 0 ? { ...sheet.cellFormats, ...Object.fromEntries(missingSampleFormats) } : sheet.cellFormats, charts: missingSampleCharts.length > 0 ? [...(sheet.charts ?? []), ...missingSampleCharts] : sheet.charts }; }) : state.workbook.sheets; const slides = state.deck.id === initialState.deck.id ? state.deck.slides.map((slide) => { const sampleSlide = sampleSlidesById[slide.id]; if (!sampleSlide?.backgroundColor || slide.backgroundColor) { return slide; } changed = true; return { ...slide, backgroundColor: sampleSlide.backgroundColor }; }) : state.deck.slides; return changed ? { ...state, word: needsSampleWordColor ? { ...state.word, html: sampleWordHtml } : state.word, workbook: { ...state.workbook, sheets }, deck: { ...state.deck, slides }, mail: { ...state.mail, messages } } : state; } export function App() { const [state, setState] = usePersistentState(STORAGE_KEY, initialState, migrateQOfficeState); const status = useMemo(() => { const updatedAt = state.activeApp === "word" ? state.word.updatedAt : state.activeApp === "sheets" ? state.workbook.updatedAt : state.activeApp === "slides" ? state.deck.updatedAt : undefined; return { savedLabel: "Сохранено локально", updatedAt }; }, [state]); function setActiveApp(activeApp: AppId) { setState((current) => ({ ...current, activeApp })); } function updateWord(word: WordDocument) { setState((current) => ({ ...current, word: { ...word, updatedAt: new Date().toISOString() } })); } function updateWorkbook(workbook: Workbook) { setState((current) => ({ ...current, workbook: { ...workbook, updatedAt: new Date().toISOString() } })); } function updateDeck(deck: SlideDeck) { setState((current) => ({ ...current, deck: { ...deck, updatedAt: new Date().toISOString() } })); } function updateMail(updater: (mail: QOfficeState["mail"]) => QOfficeState["mail"]) { setState((current) => ({ ...current, mail: updater(current.mail) })); } function setMailFolder(folder: MailMessage["folder"]) { updateMail((mail) => { const firstInFolder = mail.messages.find((message) => message.folder === folder); return { ...mail, activeFolder: folder, activeMessageId: firstInFolder?.id ?? mail.activeMessageId }; }); } const activeSurface = state.activeApp === "word" ? ( ) : state.activeApp === "sheets" ? ( ) : state.activeApp === "slides" ? ( ) : ( ); return ( {activeSurface} ); }