/
viktorphp
/
front-socket
Обзор
Документация
Войти
/
viktorphp
/
front-socket
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/entities/diary/store/model.ts
137 строк
4 KB
Иванов Виктор Евгеньевич
[feature-diadry]: добавить страницу дневника
11 апр 2026, 16:02
11 апр 2026, 16:02
e2d184b
Код
Авторство
О чём код?
'use client'; import { create } from 'zustand'; import { IDiaryEntry } from '@shared/types'; import { IDiaryStore } from './types'; /** * Zustand-стор для фичи "Дневник". * Хранит записи текущего месяца и состояние открытой записи. */ export const useDiaryStore = create<IDiaryStore>((set) => ({ entriesByDate: {}, currentEntry: null, isLoadingEntries: false, isLoadingEntry: false, /** * Принимает плоский массив записей и группирует их по дате (YYYY-MM-DD). * Заменяет весь кеш записей. */ setEntriesByDate: (entries: IDiaryEntry[]) => { // Защита: бэкенд может вернуть объект пагинации вместо чистого массива // eslint-disable-next-line @typescript-eslint/no-explicit-any const raw = entries as any; let list: IDiaryEntry[] = []; if (Array.isArray(raw)) { list = raw; } else if (raw && Array.isArray(raw.data)) { list = raw.data; } else if (raw && Array.isArray(raw.items)) { list = raw.items; } else if (raw && Array.isArray(raw.entries)) { list = raw.entries; } else { console.warn( 'setEntriesByDate: неожиданный формат данных от бэкенда:', raw ); list = []; } const grouped: Record<string, IDiaryEntry[]> = {}; list.forEach((entry) => { // Берём только дату без времени (поле date уже в формате YYYY-MM-DD) const key = entry.date; if (!grouped[key]) grouped[key] = []; grouped[key].push(entry); }); // Сортируем записи внутри каждого дня по createdAt (самые новые первыми) Object.keys(grouped).forEach((key) => { grouped[key].sort( (a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() ); }); set({ entriesByDate: grouped }); }, setCurrentEntry: (entry) => set({ currentEntry: entry }), setIsLoadingEntries: (loading) => set({ isLoadingEntries: loading }), setIsLoadingEntry: (loading) => set({ isLoadingEntry: loading }), /** * Обновляет данные OCR конкретного файла во всех местах хранилища: * в currentEntry и в entriesByDate. */ updateFileOcrResult: (fileId, data) => { set((state) => { // Обновляем файл в currentEntry const updatedCurrentEntry = state.currentEntry ? { ...state.currentEntry, files: state.currentEntry.files.map((f) => f.id === fileId ? { ...f, ...data } : f ), } : null; // Обновляем файл во всех записях кеша const updatedEntriesByDate: typeof state.entriesByDate = {}; Object.entries(state.entriesByDate).forEach(([date, entries]) => { updatedEntriesByDate[date] = entries.map((entry) => ({ ...entry, files: entry.files.map((f) => f.id === fileId ? { ...f, ...data } : f ), })); }); return { currentEntry: updatedCurrentEntry, entriesByDate: updatedEntriesByDate, }; }); }, /** * Удаляет запись из кеша entriesByDate по её ID. */ removeEntry: (entryId) => { set((state) => { const updatedEntriesByDate: typeof state.entriesByDate = {}; Object.entries(state.entriesByDate).forEach(([date, entries]) => { const filtered = entries.filter((e) => e.id !== entryId); if (filtered.length > 0) updatedEntriesByDate[date] = filtered; }); return { entriesByDate: updatedEntriesByDate }; }); }, /** * Удаляет файл из текущей открытой записи по его ID. */ removeFileFromCurrentEntry: (fileId) => { set((state) => ({ currentEntry: state.currentEntry ? { ...state.currentEntry, files: state.currentEntry.files.filter((f) => f.id !== fileId), } : null, })); }, /** * Заменяет список файлов в currentEntry (используется после загрузки новых файлов). */ setFilesInCurrentEntry: (files) => { set((state) => ({ currentEntry: state.currentEntry ? { ...state.currentEntry, files } : null, })); }, }));