From 4affe68e6eebf8d96451076219cb618017788695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Roig?= Date: Wed, 4 May 2022 22:46:14 +0200 Subject: [PATCH] fix(doneTracker): remove TrackerStatus done, use bool instead --- .../TrackerCard/TrackerCard.spec.tsx | 1 + src/components/TrackerList/TrackerList.tsx | 11 ---- .../TrackerListActions/TrackerListActions.tsx | 23 -------- .../forms/TrackerForm/TrackerForm.tsx | 1 + src/models/Tracker.ts | 2 + src/models/TrackerStatus.ts | 3 +- src/store/trackers/FAKE_DATA.ts | 4 ++ src/store/trackers/reducers/archive.spec.ts | 8 +-- .../trackers/reducers/markAsActive.spec.ts | 7 ++- .../trackers/reducers/markAsDone.spec.ts | 51 ------------------ src/store/trackers/reducers/markAsDone.ts | 29 ----------- src/store/trackers/reducers/unarchive.spec.ts | 2 +- src/store/trackers/trackers.selectors.spec.ts | 25 ++++++--- src/store/trackers/trackers.selectors.ts | 5 +- src/store/trackers/trackersSlice.ts | 5 -- src/store/trackers/utils.spec.ts | 52 ++++++++++--------- src/store/trackers/utils.ts | 36 ++++++++----- 17 files changed, 91 insertions(+), 174 deletions(-) delete mode 100644 src/store/trackers/reducers/markAsDone.spec.ts delete mode 100644 src/store/trackers/reducers/markAsDone.ts diff --git a/src/components/TrackerCard/TrackerCard.spec.tsx b/src/components/TrackerCard/TrackerCard.spec.tsx index 6e557d90..93eb918a 100644 --- a/src/components/TrackerCard/TrackerCard.spec.tsx +++ b/src/components/TrackerCard/TrackerCard.spec.tsx @@ -13,6 +13,7 @@ const tracker1 = { id: v4(), beginDate: subDays(new Date(), 3).toString(), duration: 13, + isDoneForToday: false, name: 'Musculation', remainingDays: 10, requiredCompletions: [ diff --git a/src/components/TrackerList/TrackerList.tsx b/src/components/TrackerList/TrackerList.tsx index 22f66032..4ac5e6b3 100644 --- a/src/components/TrackerList/TrackerList.tsx +++ b/src/components/TrackerList/TrackerList.tsx @@ -1,5 +1,4 @@ import ArchiveIcon from '@mui/icons-material/Archive'; -import DoneAllIcon from '@mui/icons-material/DoneAll'; import MovingIcon from '@mui/icons-material/Moving'; import { List, ListProps } from '@mui/material'; import { FC, useCallback, useState } from 'react'; @@ -28,7 +27,6 @@ const TrackerList: FC = ({ trackers, listProps }) => { .filter((t) => t.status === TrackerStatus.archived) .sort(sortByName); const activeTrackers = trackers.filter((t) => t.status === TrackerStatus.active).sort(sortByName); - const doneTrackers = trackers.filter((t) => t.status === TrackerStatus.done).sort(sortByName); const toggleTrackerChecked = (tracker: Tracker) => { const trackerIdx = selectedTrackers.indexOf(tracker); @@ -51,15 +49,6 @@ const TrackerList: FC = ({ trackers, listProps }) => { /> - {doneTrackers.length > 0 && } text="TERMINÉS" />} - {doneTrackers.map((t) => ( - - ))} {activeTrackers.length > 0 && } text="ACTIFS" />} {activeTrackers.map((t) => ( = ({ const atLeastOneSelectedArchived = selectedTrackers.some( (t) => t.status === TrackerStatus.archived ); - const atLeastOneSelectedDone = selectedTrackers.some((t) => t.status === TrackerStatus.done); const atLeastOneSelectedActive = selectedTrackers.some((t) => t.status === TrackerStatus.active); - const allSelectedArchived = selectedTrackers.every((t) => t.status === TrackerStatus.archived); const handleMenuClick = (event: React.MouseEvent) => { @@ -84,9 +80,6 @@ const TrackerListActions: FC = ({ const handlemarkTrackersAsActive = () => { handleAction(markTrackersAsActive, 'actif', 'success'); }; - const handlemarkTrackersAsDone = () => { - handleAction(markTrackersAsDone, 'terminé', 'success'); - }; const handleUnrchiveTrackers = () => { handleAction(unarchiveTrackers, 'désarchivé', 'success'); }; @@ -123,22 +116,6 @@ const TrackerListActions: FC = ({ MenuListProps={{ 'aria-labelledby': 'basic-button' }}> - - - - -   Terminer - - - ({ duration: '', defaultCompletions: [], entries: [], + isDoneForToday: false, name: '', requiredCompletions: [], status: TrackerStatus.active diff --git a/src/models/Tracker.ts b/src/models/Tracker.ts index b774b562..42a6616a 100644 --- a/src/models/Tracker.ts +++ b/src/models/Tracker.ts @@ -14,6 +14,7 @@ import TrackerStatus from './TrackerStatus'; * @member {number?} duration number of days the tracker is active since beginDate * @member {string} endDate when the Tracker was archived * @member {TrackerEntry[]} entries TrackerEntries related to this Tracker + * @member {boolean} isDoneForToday * @member {string} name * @member {number?} remainingDays computed attribute describing the number of days before the tracker is archived * @member {Completion[]} requiredCompletions objectives to complete the tracker @@ -27,6 +28,7 @@ export default interface Tracker { duration?: number; endDate?: string; entries: TrackerEntry[]; + isDoneForToday: boolean; name: string; remainingDays?: number; requiredCompletions: Completion[]; diff --git a/src/models/TrackerStatus.ts b/src/models/TrackerStatus.ts index e40aa3c3..9002af73 100644 --- a/src/models/TrackerStatus.ts +++ b/src/models/TrackerStatus.ts @@ -1,7 +1,6 @@ enum TrackerStatus { active, // todo for the current day - archived, // terminated until unarchived - done // done for the current day + archived // terminated until unarchived } export default TrackerStatus; diff --git a/src/store/trackers/FAKE_DATA.ts b/src/store/trackers/FAKE_DATA.ts index 46cb5640..592a6b9b 100644 --- a/src/store/trackers/FAKE_DATA.ts +++ b/src/store/trackers/FAKE_DATA.ts @@ -20,6 +20,7 @@ export const testTracker1: Tracker = { } ], duration: 13, + isDoneForToday: false, name: 'Musculation', remainingDays: 10, requiredCompletions: [ @@ -42,6 +43,7 @@ export const testTracker2: Tracker = { beginDate: subDays(new Date(), 10).toString(), duration: 70, entries: [], + isDoneForToday: false, name: 'Eat', requiredCompletions: [ { @@ -59,6 +61,7 @@ export const testTracker4: Tracker = { beginDate: new Date().toString(), defaultCompletions: [], entries: [], + isDoneForToday: false, name: 'Wake up', requiredCompletions: [], status: TrackerStatus.active @@ -75,6 +78,7 @@ export const testTracker3: Tracker = { } ], entries: [], + isDoneForToday: false, name: 'Drink', requiredCompletions: [ { diff --git a/src/store/trackers/reducers/archive.spec.ts b/src/store/trackers/reducers/archive.spec.ts index 5262d830..8882f267 100644 --- a/src/store/trackers/reducers/archive.spec.ts +++ b/src/store/trackers/reducers/archive.spec.ts @@ -20,7 +20,7 @@ describe('trackers reducer', () => { status: SliceStatus.idle, trackers: [ { ...testTracker1, status: TrackerStatus.active }, - { ...testTracker2, status: TrackerStatus.done } + { ...testTracker2, isDoneForToday: true } ] }, archiveTracker(testTracker1.id) @@ -29,7 +29,7 @@ describe('trackers reducer', () => { const t2 = finalState.trackers.find((t) => t.id === testTracker2Id)!; expect(isSameDay(new Date(t1.endDate!), new Date())).toBeTruthy(); expect(t1.status).toBe(TrackerStatus.archived); - expect(t2.status).toBe(TrackerStatus.done); + expect(t2.isDoneForToday).toBeTruthy(); }); it('should archive multiple trackers and set its endDate', () => { const finalState = trackersReducer( @@ -38,7 +38,7 @@ describe('trackers reducer', () => { status: SliceStatus.idle, trackers: [ { ...testTracker1, status: TrackerStatus.active }, - { ...testTracker2, status: TrackerStatus.done }, + { ...testTracker2, isDoneForToday: true }, { ...testTracker3, status: TrackerStatus.active } ] }, @@ -49,7 +49,7 @@ describe('trackers reducer', () => { expect(isSameDay(new Date(t1.endDate!), new Date())).toBeTruthy(); expect(isSameDay(new Date(t2.endDate!), new Date())).toBeTruthy(); expect(t1.status).toBe(TrackerStatus.archived); - expect(t2.status).toBe(TrackerStatus.archived); + expect(t2.isDoneForToday).toBeTruthy(); }); }); }); diff --git a/src/store/trackers/reducers/markAsActive.spec.ts b/src/store/trackers/reducers/markAsActive.spec.ts index 8c2f4469..a52ccc66 100644 --- a/src/store/trackers/reducers/markAsActive.spec.ts +++ b/src/store/trackers/reducers/markAsActive.spec.ts @@ -39,7 +39,12 @@ describe('trackers reducer', () => { trackers: [ { ...testTracker1, status: TrackerStatus.archived }, { ...testTracker2, status: TrackerStatus.active }, - { ...testTracker3, status: TrackerStatus.done, endDate: new Date().toString() } + { + ...testTracker3, + isDoneForToday: true, + status: TrackerStatus.archived, + endDate: new Date().toString() + } ] }, markTrackersAsActive([testTracker1Id, testTracker3Id]) diff --git a/src/store/trackers/reducers/markAsDone.spec.ts b/src/store/trackers/reducers/markAsDone.spec.ts deleted file mode 100644 index 62acd2f5..00000000 --- a/src/store/trackers/reducers/markAsDone.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import SliceStatus from '../../../models/SliceStatus'; -import Tracker from '../../../models/Tracker'; -import TrackerStatus from '../../../models/TrackerStatus'; -import { - testTracker1, - testTracker1Id, - testTracker2, - testTracker3, - testTracker3Id -} from '../FAKE_DATA'; -import trackersReducer, { markTrackerAsDone, markTrackersAsDone } from '../trackersSlice'; - -const isDone = (tracker: Tracker) => - tracker.status === TrackerStatus.done && tracker.endDate !== undefined; - -describe('trackers reducer', () => { - describe('Mark a tracker as done', () => { - it('should mark a tracker as done', () => { - const finalState = trackersReducer( - { - error: {}, - status: SliceStatus.idle, - trackers: [testTracker1] - }, - markTrackerAsDone(testTracker1.id) - ); - const t1 = finalState.trackers.find((t) => t.id === testTracker1Id)!; - expect(isDone(t1)).toBeTruthy(); - }); - }); - describe('Mark multiple trackers as done', () => { - it('should mark multiple trackers as done', () => { - const finalState = trackersReducer( - { - error: {}, - status: SliceStatus.idle, - trackers: [ - { ...testTracker1, status: TrackerStatus.archived }, - { ...testTracker2, status: TrackerStatus.done }, - { ...testTracker3, status: TrackerStatus.active, endDate: new Date().toString() } - ] - }, - markTrackersAsDone([testTracker1Id, testTracker3Id]) - ); - const t1 = finalState.trackers.find((t) => t.id === testTracker1Id)!; - const t3 = finalState.trackers.find((t) => t.id === testTracker3Id)!; - expect(isDone(t1)).toBeTruthy(); - expect(isDone(t3)).toBeTruthy(); - }); - }); -}); diff --git a/src/store/trackers/reducers/markAsDone.ts b/src/store/trackers/reducers/markAsDone.ts deleted file mode 100644 index 01ca8e88..00000000 --- a/src/store/trackers/reducers/markAsDone.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { PayloadAction } from '@reduxjs/toolkit'; - -import Tracker from '../../../models/Tracker'; -import TrackerStatus from '../../../models/TrackerStatus'; -import TrackersState from '../TrackersState'; - -/* eslint-disable no-param-reassign */ -const markTrackerAsDone = (tracker: Tracker) => { - tracker.endDate = new Date().toString(); - tracker.status = TrackerStatus.done; -}; -/* eslint-enable no-param-reassign */ - -const markTrackerAsDoneReducer = (state: TrackersState, action: PayloadAction) => { - const idx = state.trackers.findIndex((t) => t.id === action.payload); - if (idx !== -1) { - markTrackerAsDone(state.trackers[idx]); - } -}; -const markTrackersAsDoneReducer = ( - state: TrackersState, - action: PayloadAction> -) => { - const filteredTrackers = state.trackers.filter((t) => action.payload.includes(t.id)); - for (const tracker of filteredTrackers) { - markTrackerAsDone(tracker); - } -}; -export { markTrackerAsDoneReducer, markTrackersAsDoneReducer }; diff --git a/src/store/trackers/reducers/unarchive.spec.ts b/src/store/trackers/reducers/unarchive.spec.ts index 46fa21d5..d8ef28e9 100644 --- a/src/store/trackers/reducers/unarchive.spec.ts +++ b/src/store/trackers/reducers/unarchive.spec.ts @@ -18,7 +18,7 @@ describe('trackers reducer', () => { status: SliceStatus.idle, trackers: [ { ...testTracker1, status: TrackerStatus.active }, - { ...testTracker2, status: TrackerStatus.done }, + { ...testTracker2, isDoneForToday: true }, { ...testTracker3, status: TrackerStatus.archived } ] }, diff --git a/src/store/trackers/trackers.selectors.spec.ts b/src/store/trackers/trackers.selectors.spec.ts index 0859cc1c..b1158057 100644 --- a/src/store/trackers/trackers.selectors.spec.ts +++ b/src/store/trackers/trackers.selectors.spec.ts @@ -88,18 +88,28 @@ describe('selectTrackersDone()', () => { trackers: { ...state.trackers, trackers: [ - { ...testTracker1, status: TrackerStatus.done }, + { + ...testTracker1, + isDoneForToday: true, + status: TrackerStatus.active, + entries: [{ ...testEntry1, completions: testTracker1.requiredCompletions }] + }, testTracker2, - { ...testTracker3, status: TrackerStatus.done } + { + ...testTracker3, + isDoneForToday: true, + status: TrackerStatus.active, + entries: [{ ...testEntry1 }] + } ] } }; const { error, status, trackers } = selectTrackersDone(stateWithTrackers); expect(error).toEqual({}); expect(status).toEqual(SliceStatus.idle); - expect(trackers.length).toEqual(2); + expect(trackers.length).toEqual(1); for (const tracker of trackers) { - expect(tracker.status).toBe(TrackerStatus.done); + expect(tracker.isDoneForToday).toBeTruthy(); } }); }); @@ -115,9 +125,12 @@ describe('selectTodoTrackers()', () => { trackers: { ...state.trackers, trackers: [ - { ...testTracker1, status: TrackerStatus.archived }, + { + ...testTracker1, + entries: [{ ...testEntry1, completions: testTracker1.requiredCompletions }] + }, + { ...testTracker3, status: TrackerStatus.archived }, { ...testTracker2, dateHidden: new Date().toString() }, - { ...testTracker3, status: TrackerStatus.done }, { ...testTracker3, status: TrackerStatus.active } ] } diff --git a/src/store/trackers/trackers.selectors.ts b/src/store/trackers/trackers.selectors.ts index 7048c33e..ed8ad1f6 100644 --- a/src/store/trackers/trackers.selectors.ts +++ b/src/store/trackers/trackers.selectors.ts @@ -1,7 +1,6 @@ import { differenceInDays, isAfter, isEqual, isSameMonth, isSameYear } from 'date-fns'; import TrackerEntry from '../../models/TrackerEntry'; -import TrackerStatus from '../../models/TrackerStatus'; import { RootState } from '../store'; import { formatTrackers, @@ -21,8 +20,8 @@ const selectHiddenTrackers = (state: RootState) => { }; const selectTrackersDone = (state: RootState) => { - const newTrackers = removeHiddenTrackers( - formatTrackers(state.trackers.trackers).filter((t) => t.status === TrackerStatus.done) + const newTrackers = removeArchivedTrackers( + removeHiddenTrackers(formatTrackers(state.trackers.trackers).filter((t) => t.isDoneForToday)) ); return { diff --git a/src/store/trackers/trackersSlice.ts b/src/store/trackers/trackersSlice.ts index 58ab0434..d7a8a7e3 100644 --- a/src/store/trackers/trackersSlice.ts +++ b/src/store/trackers/trackersSlice.ts @@ -7,7 +7,6 @@ import { createTrackerReducer } from './reducers/create'; import { deleteTrackerReducer, deleteTrackersReducer } from './reducers/delete'; import { hideTrackerReducer } from './reducers/hide'; import { markTrackerAsActiveReducer, markTrackersAsActiveReducer } from './reducers/markAsActive'; -import { markTrackerAsDoneReducer, markTrackersAsDoneReducer } from './reducers/markAsDone'; import { markTrackerAsVisibleReducer } from './reducers/markAsVisible'; import { unarchiveTrackersReducer } from './reducers/unarchive'; import { completelyValidateReducer, customValidateReducer } from './reducers/validate'; @@ -42,9 +41,7 @@ export const trackersSlice = createSlice({ deleteTrackers: deleteTrackersReducer, hideTracker: hideTrackerReducer, markTrackersAsActive: markTrackersAsActiveReducer, - markTrackersAsDone: markTrackersAsDoneReducer, markTrackerAsActive: markTrackerAsActiveReducer, - markTrackerAsDone: markTrackerAsDoneReducer, markTrackerAsVisible: markTrackerAsVisibleReducer, unarchiveTrackers: unarchiveTrackersReducer } @@ -64,8 +61,6 @@ export const { hideTracker, markTrackerAsActive, markTrackersAsActive, - markTrackerAsDone, - markTrackersAsDone, markTrackerAsVisible, unarchiveTrackers } = trackersSlice.actions; diff --git a/src/store/trackers/utils.spec.ts b/src/store/trackers/utils.spec.ts index 66f98aab..f8008e6b 100644 --- a/src/store/trackers/utils.spec.ts +++ b/src/store/trackers/utils.spec.ts @@ -3,6 +3,7 @@ import { subDays } from 'date-fns'; import TrackerStatus from '../../models/TrackerStatus'; import { testEntry1, testEntry2, testTracker1 } from './FAKE_DATA'; import { + computeIfDone, computeNewStatus, computeRemainingDays, formatTrackers, @@ -20,6 +21,29 @@ describe('computeRemainingDays()', () => { }); }); +describe('computeIfDone()', () => { + it('should be done (enough entries for today)', () => { + const doneTracker = { + ...testTracker1, + entries: [testEntry1, testEntry2] + }; + expect(computeIfDone(doneTracker)).toBeTruthy(); + }); + it('should be done (no required completions but one entry without completions for today)', () => { + const doneTracker = { + ...testTracker1, + requiredCompletions: [], + entries: [ + { + ...testEntry1, + completions: [] + } + ] + }; + expect(computeIfDone(doneTracker)).toBeTruthy(); + }); +}); + describe('computeNewStatus()', () => { it('should be archived (beginDate + duration in the past)', () => { const finishedTracker = { @@ -43,13 +67,6 @@ describe('computeNewStatus()', () => { }; expect(computeNewStatus(doneTracker)).toBe(TrackerStatus.active); }); - it('should be done (enough entries for today)', () => { - const doneTracker = { - ...testTracker1, - entries: [testEntry1, testEntry2] - }; - expect(computeNewStatus(doneTracker)).toBe(TrackerStatus.done); - }); it('should be todo (no required completions and no entries for today)', () => { const doneTracker = { ...testTracker1, @@ -58,19 +75,6 @@ describe('computeNewStatus()', () => { }; expect(computeNewStatus(doneTracker)).toBe(TrackerStatus.active); }); - it('should be done (no required completions but one entry without completions for today)', () => { - const doneTracker = { - ...testTracker1, - requiredCompletions: [], - entries: [ - { - ...testEntry1, - completions: [] - } - ] - }; - expect(computeNewStatus(doneTracker)).toBe(TrackerStatus.done); - }); }); describe('remove functions', () => { @@ -81,7 +85,7 @@ describe('remove functions', () => { }, { ...testTracker1, - status: TrackerStatus.done + isDoneForToday: true }, { ...testTracker1, @@ -92,21 +96,21 @@ describe('remove functions', () => { describe('removeArchivedTrackers()', () => { it('should remove the archived trackers', () => { expect(removeArchivedTrackers(trackers).length).toBe(2); - const [t1, t2, t3] = trackers; // eslint-disable-line @typescript-eslint/no-unused-vars + const [, t2, t3] = trackers; expect(removeArchivedTrackers(trackers)).toEqual(expect.arrayContaining([t2, t3])); }); }); describe('removeDoneTrackers()', () => { it('should remove the trackers done', () => { expect(removeDoneTrackers(trackers).length).toBe(2); - const [t1, t2, t3] = trackers; // eslint-disable-line @typescript-eslint/no-unused-vars + const [t1, , t3] = trackers; expect(removeDoneTrackers(trackers)).toEqual(expect.arrayContaining([t1, t3])); }); }); describe('removeHiddenTrackers()', () => { it('should remove the hidden trackers', () => { expect(removeHiddenTrackers(trackers).length).toBe(2); - const [t1, t2, t3] = trackers; // eslint-disable-line @typescript-eslint/no-unused-vars + const [t1, t2] = trackers; expect(removeHiddenTrackers(trackers)).toEqual(expect.arrayContaining([t1, t2])); }); }); diff --git a/src/store/trackers/utils.ts b/src/store/trackers/utils.ts index a2510e95..87d14b48 100644 --- a/src/store/trackers/utils.ts +++ b/src/store/trackers/utils.ts @@ -42,18 +42,11 @@ export const computeRemainingDays = (beginDate: string, duration: number) => { return difference; }; -export const computeNewStatus = (tracker: Tracker) => { - const { beginDate, duration, entries, remainingDays, requiredCompletions, status } = tracker; - let newStatus = status; - // End tracker if needed - if ( - (remainingDays !== undefined && remainingDays < 0) || - (duration && isBefore(addDays(new Date(beginDate), duration), new Date())) - ) { - newStatus = TrackerStatus.archived; - } +export const computeIfDone = (tracker: Tracker) => { + const { entries, requiredCompletions } = tracker; + let res = false; - // Mark Tracker as done if all required completions are done + // Tracker is done if all required completions are done today // If there is no required completions, test if there is an entry for today const todayCompletions = getTodayAggregatedCompletions(entries); const remains = []; @@ -66,14 +59,28 @@ export const computeNewStatus = (tracker: Tracker) => { ); } if (remains.every((x) => x <= 0)) { - newStatus = TrackerStatus.done; + res = true; } } else { if (entries.filter((e) => isToday(new Date(e.date))).length > 0) { - newStatus = TrackerStatus.done; + res = true; } } + return res; +}; + +export const computeNewStatus = (tracker: Tracker) => { + const { beginDate, duration, remainingDays, status } = tracker; + let newStatus = status; + // Archive tracker if needed + if ( + (remainingDays !== undefined && remainingDays < 0) || + (duration && isBefore(addDays(new Date(beginDate), duration), new Date())) + ) { + newStatus = TrackerStatus.archived; + } + return newStatus; }; @@ -97,6 +104,7 @@ export const formatTrackers = (trackers: Tracker[]) => { return { ...trackerObj, + isDoneForToday: computeIfDone(trackerObj), status: computeNewStatus(trackerObj) }; }); @@ -107,7 +115,7 @@ export const removeArchivedTrackers = (trackers: Tracker[]) => trackers.filter((t) => t.status !== TrackerStatus.archived); export const removeDoneTrackers = (trackers: Tracker[]) => - trackers.filter((t) => t.status !== TrackerStatus.done); + trackers.filter((t) => !t.isDoneForToday); export const removeHiddenTrackers = (trackers: Tracker[]) => trackers.filter((t) => t.dateHidden === undefined);