todo-app

Форк
0
162 строки · 3.8 Кб
1
import { createStore, createEvent, combine, sample } from 'effector';
2
import { useUnit } from 'effector-react';
3
import { persist } from 'effector-storage';
4
import { nanoid } from 'nanoid';
5
import { $queryConfig } from './query-config';
6
import { $paginationConfig } from './pagination-config';
7
import { compareText, compareExpiresIn } from '../utils';
8
import {
9
  createStorageAdapter,
10
  compareIf,
11
  customCompareIf,
12
  excludeKey,
13
} from '@/shared/utils';
14
import { type TaskBase, type Task, type TaskId } from '@/shared/types';
15

16
const addTask = createEvent<TaskBase>();
17

18
const modifyTask = createEvent<{ id: TaskId } & TaskBase>();
19

20
const removeTask = createEvent<TaskId>();
21

22
const toggleTask = createEvent<TaskId>();
23

24
const markTaskToRemove = createEvent<TaskId>();
25

26
const unmarkTaskToRemove = createEvent<TaskId>();
27

28
sample({
29
  clock: removeTask,
30
  target: unmarkTaskToRemove,
31
});
32

33
export const $tasks = createStore<Record<TaskId, Task>>({})
34
  .on(addTask, (store, taskBase) => {
35
    const id = nanoid();
36
    const title = taskBase.title.trim();
37
    const description = taskBase.description ? taskBase.description : undefined;
38
    const expiresIn = taskBase.expiresIn ?? undefined;
39

40
    return {
41
      ...store,
42
      [id]: {
43
        id,
44
        title,
45
        description,
46
        priority: taskBase.priority,
47
        createdAt: new Date().toISOString(),
48
        expiresIn,
49
        completedIn: undefined,
50
        isCompleted: false,
51
      },
52
    };
53
  })
54
  .on(modifyTask, (store, { id, ...taskBase }) => {
55
    const title = taskBase.title.trim();
56
    const description = taskBase.description ? taskBase.description : undefined;
57
    const expiresIn = taskBase.expiresIn ?? undefined;
58

59
    return {
60
      ...store,
61
      [id]: {
62
        ...store[id],
63
        title,
64
        description,
65
        priority: taskBase.priority,
66
        expiresIn,
67
      },
68
    };
69
  })
70
  .on(removeTask, (store, taskId) => excludeKey(store, taskId))
71
  .on(toggleTask, (store, taskId) => {
72
    const isCompleted = !store[taskId].isCompleted;
73

74
    return {
75
      ...store,
76
      [taskId]: {
77
        ...store[taskId],
78
        completedIn: isCompleted ? new Date().toISOString() : undefined,
79
        isCompleted,
80
      },
81
    };
82
  });
83

84
export const $tasksToDelete = createStore<TaskId[]>([])
85
  .on(markTaskToRemove, (store, taskId) => [...store, taskId])
86
  .on(unmarkTaskToRemove, (store, taskId) =>
87
    store.filter((entry) => entry !== taskId),
88
  );
89

90
export const $tasksList = combine(
91
  $tasks,
92
  $tasksToDelete,
93
  (tasks, tasksToDelete) =>
94
    Object.values(tasks).filter((task) => !tasksToDelete.includes(task.id)),
95
);
96

97
export const $tasksFiltered = combine(
98
  $tasksList,
99
  $queryConfig,
100
  (tasks, query) =>
101
    tasks.filter(
102
      (task) =>
103
        customCompareIf(
104
          task.title.concat(task.description ?? ''),
105
          query.text,
106
          compareText,
107
        ) &&
108
        compareIf(task.priority, query.priority) &&
109
        compareIf(task.isCompleted, query.isCompleted) &&
110
        customCompareIf(task.expiresIn, query.isOverdue, compareExpiresIn),
111
    ),
112
);
113

114
export const $tasksPaged = combine(
115
  $tasksFiltered,
116
  $paginationConfig,
117
  (tasks, pagination) => {
118
    const offset = (pagination.page - 1) * pagination.size;
119

120
    return tasks.slice(offset, offset + pagination.size);
121
  },
122
);
123

124
persist({
125
  key: 'tasks',
126
  store: $tasks,
127
  adapter: createStorageAdapter(),
128
});
129

130
const useTasks = () => {
131
  return useUnit($tasksPaged);
132
};
133

134
const useTasksCount = () => {
135
  return useUnit($tasksFiltered).length;
136
};
137

138
const useTask = (id?: TaskId) => {
139
  const tasks = useUnit($tasks);
140
  const tasksToDelete = useUnit($tasksToDelete);
141

142
  if (id === undefined || tasksToDelete.includes(id)) {
143
    return null;
144
  }
145

146
  return tasks?.[id] ?? null;
147
};
148

149
export const events = {
150
  addTask,
151
  modifyTask,
152
  removeTask,
153
  toggleTask,
154
  markTaskToRemove,
155
  unmarkTaskToRemove,
156
};
157

158
export const selectors = {
159
  useTasks,
160
  useTasksCount,
161
  useTask,
162
};
163

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.