react-weekly-planning 1.0.39 → 1.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/components/AddTask/index.js +16 -0
  2. package/dist/components/CalendarForWeek.js +30 -0
  3. package/dist/components/CalendarForday.js +22 -0
  4. package/dist/components/DayContainer/index.js +15 -0
  5. package/dist/components/GroupContainer/index.js +15 -0
  6. package/dist/components/GroupsHeadContainer/index.js +8 -0
  7. package/dist/components/SumHoursContainer/index.js +15 -0
  8. package/dist/components/SumHoursHead/index.js +8 -0
  9. package/dist/components/TaskContainer/TaskVirtual.js +18 -0
  10. package/dist/components/TaskContainer/index.js +36 -0
  11. package/dist/components/TaskList/index.js +4 -0
  12. package/dist/components/VirtualGroupRow.js +64 -0
  13. package/dist/components/VirtualGroupRowDay.js +49 -0
  14. package/dist/components/index.js +70 -0
  15. package/dist/components/style.css +167 -0
  16. package/dist/contexts/CalendarContext.js +8 -0
  17. package/dist/contexts/CalendarTaskContext.js +32 -0
  18. package/dist/definitions/index.js +1 -0
  19. package/dist/hooks/useCalendarDateState.js +19 -0
  20. package/dist/hooks/useCalendarTask.js +191 -0
  21. package/dist/hooks/useContainerScroll.js +14 -0
  22. package/dist/hooks/useData.js +7 -0
  23. package/dist/hooks/useGridContainer.js +24 -0
  24. package/dist/hooks/useIntersectionObserver.js +19 -0
  25. package/dist/hooks/useMainContainerItemContent.js +16 -0
  26. package/dist/hooks/useWindowsSize.js +19 -0
  27. package/dist/index.js +19 -0
  28. package/dist/lib/slyles.js +21 -0
  29. package/dist/lib/utils.js +657 -0
  30. package/dist/types/components/AddTask/index.d.ts +3 -0
  31. package/dist/types/components/CalendarForWeek.d.ts +3 -0
  32. package/dist/types/components/CalendarForday.d.ts +5 -0
  33. package/dist/types/components/DayContainer/index.d.ts +3 -0
  34. package/dist/types/components/GroupContainer/index.d.ts +3 -0
  35. package/dist/types/components/GroupsHeadContainer/index.d.ts +3 -0
  36. package/dist/types/components/SumHoursContainer/index.d.ts +3 -0
  37. package/dist/types/components/SumHoursHead/index.d.ts +3 -0
  38. package/dist/types/components/TaskContainer/TaskVirtual.d.ts +4 -0
  39. package/dist/types/components/TaskContainer/index.d.ts +3 -0
  40. package/dist/types/components/TaskList/index.d.ts +5 -0
  41. package/dist/types/components/VirtualGroupRow.d.ts +18 -0
  42. package/dist/types/components/VirtualGroupRowDay.d.ts +19 -0
  43. package/dist/types/components/index.d.ts +65 -0
  44. package/dist/types/contexts/CalendarContext.d.ts +7 -0
  45. package/dist/types/contexts/CalendarTaskContext.d.ts +23 -0
  46. package/dist/types/definitions/index.d.ts +417 -0
  47. package/dist/types/hooks/useCalendarDateState.d.ts +6 -0
  48. package/dist/types/hooks/useCalendarTask.d.ts +16 -0
  49. package/dist/types/hooks/useContainerScroll.d.ts +3 -0
  50. package/dist/types/hooks/useData.d.ts +4 -0
  51. package/dist/types/hooks/useGridContainer.d.ts +5 -0
  52. package/dist/types/hooks/useIntersectionObserver.d.ts +5 -0
  53. package/dist/types/hooks/useMainContainerItemContent.d.ts +4 -0
  54. package/dist/types/hooks/useWindowsSize.d.ts +4 -0
  55. package/dist/types/index.d.ts +16 -0
  56. package/dist/types/lib/slyles.d.ts +4 -0
  57. package/dist/types/lib/utils.d.ts +90 -0
  58. package/package.json +1 -1
@@ -0,0 +1,191 @@
1
+ import { useEffect, useRef, useState, useMemo } from "react";
2
+ import { getHash, updateOffsetWithDateCalendar } from "../lib/utils";
3
+ const STORAGE_KEY = "calendar_tasks";
4
+ export function useCalendarTask(hashScope, timeZone) {
5
+ const tasksRef = useRef({ buckets: {}, dataLength: 0, taskCache: {} });
6
+ const scheduleCleanRef = useRef(null);
7
+ const [render, forceRender] = useState(0);
8
+ const cleanExpiredTasks = () => {
9
+ const store = tasksRef.current;
10
+ let newDataLength = 0;
11
+ for (const hash in store.buckets) {
12
+ const bucket = store.buckets[hash];
13
+ const validTasks = bucket.list.filter(isValidTask);
14
+ newDataLength += validTasks.length;
15
+ if (validTasks.length === bucket.list.length)
16
+ continue;
17
+ const newIndexMap = {};
18
+ let sumOfTaskDuration = 0;
19
+ validTasks.forEach((task, index) => {
20
+ newIndexMap[task.id] = index;
21
+ sumOfTaskDuration += task.taskEnd - task.taskStart;
22
+ });
23
+ store.buckets[hash] = {
24
+ list: validTasks,
25
+ indexMap: newIndexMap,
26
+ sumOfTaskDuration,
27
+ };
28
+ }
29
+ store.dataLength = newDataLength;
30
+ saveToStorage();
31
+ forceRender((x) => x + 1);
32
+ };
33
+ const cleanExpiredTasksByHash = (hash) => {
34
+ const bucket = tasksRef.current.buckets[hash];
35
+ if (!bucket)
36
+ return;
37
+ const validTasks = bucket.list.filter(isValidTask);
38
+ if (validTasks.length === bucket.list.length)
39
+ return;
40
+ const removedCount = bucket.list.length - validTasks.length;
41
+ tasksRef.current.dataLength -= removedCount;
42
+ const newIndexMap = {};
43
+ let sumOfTaskDuration = 0;
44
+ validTasks.forEach((task, index) => {
45
+ newIndexMap[task.id] = index;
46
+ sumOfTaskDuration += task.taskEnd - task.taskStart;
47
+ });
48
+ tasksRef.current.buckets[hash] = {
49
+ list: validTasks,
50
+ indexMap: newIndexMap,
51
+ sumOfTaskDuration,
52
+ };
53
+ saveToStorage();
54
+ forceRender((x) => x + 1);
55
+ };
56
+ if (!scheduleCleanRef.current) {
57
+ scheduleCleanRef.current = (() => {
58
+ let timeout;
59
+ return () => {
60
+ clearTimeout(timeout);
61
+ timeout = setTimeout(() => {
62
+ if ("requestIdleCallback" in window) {
63
+ requestIdleCallback(() => {
64
+ cleanExpiredTasks();
65
+ });
66
+ }
67
+ else {
68
+ setTimeout(() => cleanExpiredTasks(), 0);
69
+ }
70
+ }, 2000);
71
+ };
72
+ })();
73
+ }
74
+ const scheduleClean = scheduleCleanRef.current;
75
+ const getNow = () => {
76
+ const now = new Date();
77
+ if (timeZone) {
78
+ return new Date(now.toLocaleString("en-US", { timeZone }));
79
+ }
80
+ return now;
81
+ };
82
+ const isValidTask = (task) => {
83
+ if (!task.taskExpiryDate)
84
+ return false;
85
+ return new Date(task.taskExpiryDate) > getNow();
86
+ };
87
+ // 💾 SAVE → O(1)
88
+ const saveToStorage = () => {
89
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(tasksRef.current));
90
+ };
91
+ // 📦 LOAD (sans clean)
92
+ useEffect(() => {
93
+ const stored = localStorage.getItem(STORAGE_KEY);
94
+ if (!stored)
95
+ return;
96
+ tasksRef.current = JSON.parse(stored);
97
+ forceRender((x) => x + 1);
98
+ }, []);
99
+ // ➕ ADD → O(1)
100
+ const addTask = (task) => {
101
+ const offset = updateOffsetWithDateCalendar(task.taskDate);
102
+ const hash = getHash(offset, task.groupId, task.dayIndex)[hashScope];
103
+ if (!tasksRef.current.buckets[hash]) {
104
+ tasksRef.current.buckets[hash] = {
105
+ list: [],
106
+ indexMap: {},
107
+ sumOfTaskDuration: 0,
108
+ };
109
+ }
110
+ const bucket = tasksRef.current.buckets[hash];
111
+ const index = bucket.list.length;
112
+ bucket.list.push(Object.assign(Object.assign({}, task), { hash }));
113
+ bucket.indexMap[task.id] = index;
114
+ bucket.sumOfTaskDuration += task.taskEnd - task.taskStart;
115
+ tasksRef.current.dataLength++;
116
+ saveToStorage();
117
+ scheduleClean();
118
+ forceRender((x) => x + 1);
119
+ };
120
+ const getTasks = (hash) => {
121
+ const bucket = tasksRef.current.buckets[hash];
122
+ if (!bucket)
123
+ return [];
124
+ return bucket.list;
125
+ };
126
+ const getTask = (hash, taskId) => {
127
+ const bucket = tasksRef.current.buckets[hash];
128
+ if (!bucket)
129
+ return;
130
+ const index = bucket.indexMap[taskId];
131
+ if (index === undefined)
132
+ return;
133
+ return bucket.list[index];
134
+ };
135
+ // ✏️ UPDATE → O(1)
136
+ const updateTask = (hash, taskId, updatedTask) => {
137
+ const bucket = tasksRef.current.buckets[hash];
138
+ if (!bucket)
139
+ return;
140
+ const index = bucket.indexMap[taskId];
141
+ if (index === undefined)
142
+ return;
143
+ const oldTAskDuration = bucket.list[index].taskEnd - bucket.list[index].taskStart;
144
+ if (updatedTask.taskEnd && updatedTask.taskStart) {
145
+ const newTAskDuration = updatedTask.taskEnd - updatedTask.taskStart;
146
+ if (newTAskDuration !== oldTAskDuration) {
147
+ bucket.sumOfTaskDuration = bucket.sumOfTaskDuration - oldTAskDuration + newTAskDuration;
148
+ }
149
+ }
150
+ bucket.list[index] = Object.assign(Object.assign({}, bucket.list[index]), updatedTask);
151
+ saveToStorage();
152
+ scheduleClean();
153
+ forceRender((x) => x + 1);
154
+ };
155
+ // ❌ DELETE → O(1)
156
+ const deleteTask = (hash, taskId) => {
157
+ const bucket = tasksRef.current.buckets[hash];
158
+ if (!bucket)
159
+ return;
160
+ const index = bucket.indexMap[taskId];
161
+ if (index === undefined)
162
+ return;
163
+ const lastIndex = bucket.list.length - 1;
164
+ const lastTask = bucket.list[lastIndex];
165
+ const oldTAskDuration = bucket.list[index].taskEnd - bucket.list[index].taskStart;
166
+ [bucket.list[index], bucket.list[lastIndex]] = [
167
+ bucket.list[lastIndex],
168
+ bucket.list[index],
169
+ ];
170
+ bucket.indexMap[lastTask.id] = index;
171
+ bucket.list.pop();
172
+ delete bucket.indexMap[taskId];
173
+ bucket.sumOfTaskDuration -= oldTAskDuration;
174
+ tasksRef.current.dataLength--;
175
+ saveToStorage();
176
+ scheduleClean();
177
+ forceRender((x) => x + 1);
178
+ };
179
+ const tasks = useMemo(() => (Object.assign({}, tasksRef.current)), [render]);
180
+ return {
181
+ tasks,
182
+ addTask,
183
+ getTasks,
184
+ updateTask,
185
+ deleteTask,
186
+ cleanExpiredTasks,
187
+ cleanExpiredTasksByHash,
188
+ isValidTask,
189
+ getTask
190
+ };
191
+ }
@@ -0,0 +1,14 @@
1
+ import { useState, useEffect } from "react";
2
+ export function useContainerScroll(mainContaierRef, cardHeight, gridGap) {
3
+ const [sliceIndex, setSliceIndex] = useState(0);
4
+ useEffect(() => {
5
+ const mainContainer = mainContaierRef.current;
6
+ const handleScroll = () => {
7
+ const computeIndex = Math.floor(mainContainer.scrollTop / (cardHeight + gridGap));
8
+ setSliceIndex(computeIndex);
9
+ };
10
+ mainContainer.addEventListener("scroll", handleScroll);
11
+ return () => mainContainer.removeEventListener("scroll", handleScroll);
12
+ }, [cardHeight, gridGap]);
13
+ return { sliceIndex };
14
+ }
@@ -0,0 +1,7 @@
1
+ import { useMemo } from "react";
2
+ export const useData = (sliceIndex, itemsByLine, windowLines, tasks, bottomBufferSize, topBufferSize) => {
3
+ console.log(sliceIndex, itemsByLine, windowLines, tasks, "virtual");
4
+ const visibleTasks = useMemo(() => tasks.slice(Math.max(sliceIndex - topBufferSize, 0) * itemsByLine, Math.min(tasks.length, (windowLines + bottomBufferSize) * itemsByLine +
5
+ sliceIndex * itemsByLine)), [sliceIndex, itemsByLine, windowLines, tasks]);
6
+ return { visibleTasks };
7
+ };
@@ -0,0 +1,24 @@
1
+ import { useEffect, useRef, useState } from "react";
2
+ import { useWindowSize } from "./useWindowsSize";
3
+ export const useGridContainer = (gridContaineRef) => {
4
+ const [cardCompH, setCardCompH] = useState(0);
5
+ const [itemsByLine, setItemsByLines] = useState(1);
6
+ const cardRef = useRef(undefined);
7
+ const { width } = useWindowSize();
8
+ useEffect(() => {
9
+ if (typeof window === "undefined")
10
+ return;
11
+ //si le parent n'a aucun enfant on sort
12
+ if (gridContaineRef.current.hasChildNodes() === false)
13
+ return;
14
+ //la hauteur du premier enfant de la grid
15
+ const cardH = gridContaineRef.current.firstChild.clientHeight;
16
+ if (cardH !== cardCompH) {
17
+ const gridW = gridContaineRef.current.clientWidth;
18
+ const cardW = gridContaineRef.current.firstChild.clientWidth;
19
+ setCardCompH(cardH);
20
+ setItemsByLines(Math.floor(gridW / cardW));
21
+ }
22
+ }, [width]);
23
+ return { cardCompH, cardRef, itemsByLine };
24
+ };
@@ -0,0 +1,19 @@
1
+ import { useEffect, useState } from "react";
2
+ export function useIntersectionObserver(elementRef, { threshold = 0, root = null, rootMargin = "0%", freezeOnceVisible = false, } = {}) {
3
+ const [entry, setEntry] = useState();
4
+ const frozen = (entry === null || entry === void 0 ? void 0 : entry.isIntersecting) && freezeOnceVisible;
5
+ const updateEntry = ([entry]) => {
6
+ setEntry(entry);
7
+ };
8
+ useEffect(() => {
9
+ const node = elementRef === null || elementRef === void 0 ? void 0 : elementRef.current; // DOM node
10
+ const hasIOSupport = !!window.IntersectionObserver;
11
+ if (!hasIOSupport || frozen || !node)
12
+ return;
13
+ const observerParams = { threshold, root, rootMargin };
14
+ const observer = new IntersectionObserver(updateEntry, observerParams);
15
+ observer.observe(node);
16
+ return () => observer.disconnect();
17
+ }, [elementRef, JSON.stringify(threshold), root, rootMargin, frozen]);
18
+ return entry;
19
+ }
@@ -0,0 +1,16 @@
1
+ import { useEffect, useState } from "react";
2
+ export function useMainContainerContent(mainContaierRef, cardCompH) {
3
+ const [windowLines, setWindowLine] = useState(0);
4
+ useEffect(() => {
5
+ if (typeof window === "undefined")
6
+ return;
7
+ if (cardCompH === 0)
8
+ return;
9
+ const windowContent = Math.ceil(mainContaierRef.current.clientHeight / cardCompH);
10
+ if (windowContent !== windowLines)
11
+ setWindowLine(windowContent);
12
+ }, [cardCompH]);
13
+ //le nombre de lignes que peut contenir la fenetre
14
+ return { windowLines };
15
+ }
16
+ export default useMainContainerContent;
@@ -0,0 +1,19 @@
1
+ import { useState, useEffect } from 'react';
2
+ export function useWindowSize() {
3
+ const [windowSize, setWindowSize] = useState({
4
+ width: window.innerWidth,
5
+ height: window.innerHeight,
6
+ });
7
+ useEffect(() => {
8
+ function handleResize() {
9
+ setWindowSize({
10
+ width: window.innerWidth,
11
+ height: window.innerHeight,
12
+ });
13
+ }
14
+ window.addEventListener('resize', handleResize);
15
+ return () => window.removeEventListener('resize', handleResize);
16
+ }, []);
17
+ return windowSize;
18
+ }
19
+ // Utilisation dans un composant
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ // src/index.ts
2
+ // 1. Tu exportes ton composant principal
3
+ export { default as Calendar } from './components/index';
4
+ // 2. Tu exportes tout le contenu de ton fichier utils
5
+ export * from './lib/utils';
6
+ export * from './definitions/index';
7
+ export * from './hooks/useCalendarTask';
8
+ export * from './contexts/CalendarTaskContext';
9
+ export * from './components/TaskContainer/';
10
+ export * from './components/TaskContainer/TaskVirtual';
11
+ export * from './components/AddTask';
12
+ export * from './components/SumHoursContainer';
13
+ export * from './components/SumHoursHead';
14
+ export * from './components/GroupContainer';
15
+ export * from './components/VirtualGroupRow';
16
+ export * from './components/VirtualGroupRowDay';
17
+ export * from './components/DayContainer';
18
+ export * from './hooks/useCalendarDateState';
19
+ export * from './contexts/CalendarTaskContext';
@@ -0,0 +1,21 @@
1
+ export const theadTrStyle = {
2
+ color: "#0f5173",
3
+ fontWeight: "300",
4
+ position: "sticky",
5
+ top: -1,
6
+ };
7
+ export const groupTdStyle = {
8
+ height: "auto",
9
+ width: "150px",
10
+ };
11
+ export const groupContainerStyle = {
12
+ width: "100%",
13
+ height: "100%",
14
+ display: "flex",
15
+ alignItems: "center",
16
+ justifyContent: "space-between",
17
+ gap: "0.75rem", // Correspond à gap-3
18
+ padding: "0.75rem", // Correspond à p-3
19
+ color: "#0f5173",
20
+ cursor: "pointer",
21
+ };