Skip to content

Commit

Permalink
feat(impact): measure & display (#130)
Browse files Browse the repository at this point in the history
  • Loading branch information
mehdilouraoui committed Mar 4, 2022
1 parent 93c0709 commit 2e84d68
Show file tree
Hide file tree
Showing 31 changed files with 351 additions and 181 deletions.
12 changes: 9 additions & 3 deletions src/common/utils/index.ts
Expand Up @@ -49,11 +49,17 @@ export const notImplemented = (..._args: Any[]): Any | Promise<Any> => {
throw new Error("Not implemented");
};

// TODO do propre things ...
export const toOneDecimalsFloat = (n: number): number =>
Math.round(n * 10) / 10;
export const toTwoDecimalsFloat = (n: number): number =>
Math.round(n * 100) / 100;

export const getPercentage = (current: number, total: number): number =>
(current / total) * 100;
toTwoDecimalsFloat((current / total) * 100);

export const bytesToMegabytes = (bytes: number): number =>
+(bytes / 1.0e6).toFixed(1);
toOneDecimalsFloat(bytes / 1.0e6);

export const bytesToKilobytes = (bytes: number): number =>
+(bytes / 1000).toFixed(1);
toOneDecimalsFloat(bytes / 1000);
30 changes: 24 additions & 6 deletions src/renderer/components/viewer/CirclePacking.tsx
@@ -1,5 +1,3 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
import type { ComputedDatum } from "@nivo/circle-packing";
import { ResponsiveCirclePacking } from "@nivo/circle-packing";
import debounce from "lodash/debounce";
Expand Down Expand Up @@ -30,6 +28,7 @@ import {
} from "../../utils/tag-manager";
import { Menu } from "../menu/Menu";
import style from "./CirclePacking.module.scss";
import type { OnBlur } from "./CirclePackingCancellableFocusZone";
import { CirclePackingCancellableFocusZone } from "./CirclePackingCancellableFocusZone";
import { CirclePackingTooltip } from "./CirclePackingTooltip";

Expand All @@ -51,7 +50,7 @@ export const CirclePacking: React.FC = () => {
usePstFMInfosStore();

const {
setHoveredId,
setHoveredNode,
addChildrenMarkedToKeep,
addChildrenMarkedToDelete,
markedToDelete,
Expand Down Expand Up @@ -113,7 +112,7 @@ export const CirclePacking: React.FC = () => {
}

setMainInfos(node);
setHoveredId(node.id);
setHoveredNode(node);
}, 500);

const handleMouseLeave: CirclePackingCommonProps["onMouseLeave"] = () => {
Expand All @@ -123,11 +122,30 @@ export const CirclePacking: React.FC = () => {
};

const handleClick: CirclePackingCommonProps["onClick"] = (node) => {
if (isMailViewerObject(node.data)) startFocus();
if (isMailViewerObject(node.data)) {
console.log({ node });
setMainInfos(node);
startFocus();
}

computeNextView(node);
};

const handleLostFocus = debounce<NonNullable<OnBlur["onBlur"]>>((evt) => {
const elt = document.elementFromPoint(evt.clientX, evt.clientY);

elt?.dispatchEvent(
new MouseEvent(
"click", // or "mousedown" if the canvas listens for such an event
{
bubbles: true,
clientX: evt.clientX,
clientY: evt.clientY,
}
)
);
}, 200);

const handleBorderColor: CirclePackingCommonProps["borderColor"] = (node) =>
handleFocusItemBorderColor(node, mainInfos, isInfoFocus);

Expand Down Expand Up @@ -164,7 +182,7 @@ export const CirclePacking: React.FC = () => {
{...commonProperties}
/>
</div>
<CirclePackingCancellableFocusZone />
<CirclePackingCancellableFocusZone onBlur={handleLostFocus} />
<Menu />
</>
);
Expand Down
Expand Up @@ -6,15 +6,24 @@ import React from "react";
import { usePstFMInfosStore } from "../../store/PstFMInfosStore";
import style from "./CirclePacking.module.scss";

export const CirclePackingCancellableFocusZone: React.FC = () => {
export interface OnBlur {
onBlur?: (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
}

export const CirclePackingCancellableFocusZone: React.FC<OnBlur> = ({
onBlur,
}) => {
const { isInfoFocus, cancelFocus } = usePstFMInfosStore();

if (!isInfoFocus) return null;

return (
<div
className={style.circlePackingCancellableZone}
onClick={cancelFocus}
onClick={(evt) => {
cancelFocus();
onBlur?.(evt);
}}
/>
);
};
7 changes: 4 additions & 3 deletions src/renderer/hooks/useDymViewerNavigation.tsx
Expand Up @@ -27,7 +27,7 @@ import {
createDomain,
createMails,
createYears,
getAggregatedDomainCount,
getAggregatedDomains,
getMailsByDym,
getTotalLevelMail,
getUniqueCorrespondantsByDomain,
Expand Down Expand Up @@ -82,10 +82,10 @@ export const useDymViewerNavigation = (): UseDomainsYearMailsProps => {
useState<ViewState<DefaultViewerObject<string>>>();

const createInitialView = useCallback(() => {
const aggregatedDomainCount = getAggregatedDomainCount(pstFile!);
const aggregatedDomain = getAggregatedDomains(pstFile!);

const computedInitialView = {
elements: createDomain(aggregatedDomainCount),
elements: createDomain(aggregatedDomain),
type: DOMAIN as ViewType,
};

Expand Down Expand Up @@ -146,6 +146,7 @@ export const useDymViewerNavigation = (): UseDomainsYearMailsProps => {
uniqueCorrespondantsByDomain,
node.id
);

const totalLevelMails = getTotalLevelMail(elements);
setTotalMailPerLevel(totalLevelMails);

Expand Down
40 changes: 40 additions & 0 deletions src/renderer/store/ImpactStore.ts
@@ -0,0 +1,40 @@
import type { PstExtractTables } from "@common/modules/pst-extractor/type";
import createHook from "zustand/index";
import create from "zustand/vanilla";

export interface ImpactState {
size: number;
toDeleteIDs: Set<string>;
updateToDeleteImpact: (ids: string[], impact: "add" | "delete") => void;
}
let attachementMap: PstExtractTables["attachements"] | undefined = void 0;
const impactStore = create<ImpactState>((set) => ({
size: 0,
toDeleteIDs: new Set(),
updateToDeleteImpact: (ids: string[], impact: "add" | "delete"): void => {
set((state) => {
ids.forEach((id) => state.toDeleteIDs[impact](id));
if (!attachementMap) return;
const totalDeletedSize = [...state.toDeleteIDs].reduce(
(acc, id) =>
acc +
(attachementMap!
.get(id)
?.reduce((accAtt, att) => accAtt + att.filesize, 0) ??
0),

0
);
return { ...state, size: totalDeletedSize };
});
},
}));

const impactStoreHook = createHook(impactStore);
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types -- Deal with it.
export const useImpactStore = (am?: PstExtractTables["attachements"]) => {
if (!attachementMap) {
attachementMap = am;
}
return impactStoreHook();
};
1 change: 1 addition & 0 deletions src/renderer/store/PstFileSizeStore.tsx
Expand Up @@ -47,5 +47,6 @@ export const setInitialFileSizePerLevel = (): void => {

/**
* Consume vanilla attachmentCount store in React scope with a hook.
* @returns totalFileSize: in Mo
*/
export const usePstFileSizeStore = createHook(pstFileSizeStore);
50 changes: 34 additions & 16 deletions src/renderer/store/TagManagerStore.tsx
@@ -1,46 +1,59 @@
import type { ComputedDatum } from "@nivo/circle-packing";
import { atom, useAtom } from "jotai/index";
import type { SetStateAction } from "react";
import { useCallback } from "react";

import type { ViewerObject } from "../utils/dashboard-viewer-dym";
import { useImpactStore } from "./ImpactStore";
import { usePstStore } from "./PSTStore";

type HoveredNode = ComputedDatum<ViewerObject<string>>;
export interface UseTagManagerStore {
markedToDelete: string[];
setMarkedToDelete: (update: SetStateAction<string[]>) => void;
markedToKeep: string[];
setMarkedToKeep: (update: SetStateAction<string[]>) => void;
hoveredId: string;
setHoveredId: (update: SetStateAction<string>) => void;
hoveredNode: HoveredNode | null;
setHoveredNode: (update: SetStateAction<HoveredNode | null>) => void;
addMarkedToDelete: () => void;
addMarkedToKeep: () => void;
addChildrenMarkedToDelete: (idsToDelete: string[]) => void;
addChildrenMarkedToKeep: (idsToKeep: string[]) => void;
}

const markedToDeleteAtom = atom<string[]>([""]);
const markedToKeepAtom = atom<string[]>([""]);
const hoveredIdAtom = atom<string>("");
const markedToDeleteAtom = atom<string[]>([]);
const markedToKeepAtom = atom<string[]>([]);
const hoveredNodeAtom = atom<HoveredNode | null>(null);

export const useTagManagerStore = (): UseTagManagerStore => {
const [markedToDelete, setMarkedToDelete] = useAtom(markedToDeleteAtom);
const [markedToKeep, setMarkedToKeep] = useAtom(markedToKeepAtom);
const [hoveredId, setHoveredId] = useAtom(hoveredIdAtom);
const [hoveredNode, setHoveredNode] = useAtom(hoveredNodeAtom);
const { extractTables } = usePstStore();
const { updateToDeleteImpact } = useImpactStore(
extractTables?.attachements
);

// DELETE LOGIC
const addMarkedToDelete = useCallback(() => {
if (markedToKeep.includes(hoveredId)) {
if (!hoveredNode) return;
if (markedToKeep.includes(hoveredNode.id)) {
const removeCurrentFromKeep = markedToKeep.filter(
(element) => element !== hoveredId
(elementId) => elementId !== hoveredNode.id
);
setMarkedToKeep(removeCurrentFromKeep);
}

const updatedMarkedToDelete = [
...new Set([...markedToDelete, hoveredId]),
...new Set([...markedToDelete, hoveredNode.id]),
];
setMarkedToDelete(updatedMarkedToDelete);
updateToDeleteImpact(hoveredNode.data.ids, "add");
}, [
hoveredId,
hoveredNode,
markedToDelete,
markedToKeep,
updateToDeleteImpact,
setMarkedToDelete,
setMarkedToKeep,
]);
Expand All @@ -59,19 +72,24 @@ export const useTagManagerStore = (): UseTagManagerStore => {

// KEEP LOGIC
const addMarkedToKeep = useCallback(() => {
if (markedToDelete.includes(hoveredId)) {
if (!hoveredNode) return;
if (markedToDelete.includes(hoveredNode.id)) {
const removeCurrentFromDelete = markedToDelete.filter(
(element) => element !== hoveredId
(element) => element !== hoveredNode.id
);
setMarkedToDelete(removeCurrentFromDelete);
}

const updatedMarkedToKeep = [...new Set([...markedToKeep, hoveredId])];
const updatedMarkedToKeep = [
...new Set([...markedToKeep, hoveredNode.id]),
];
setMarkedToKeep(updatedMarkedToKeep);
updateToDeleteImpact(hoveredNode.data.ids, "delete");
}, [
hoveredId,
hoveredNode,
markedToDelete,
markedToKeep,
updateToDeleteImpact,
setMarkedToDelete,
setMarkedToKeep,
]);
Expand All @@ -93,10 +111,10 @@ export const useTagManagerStore = (): UseTagManagerStore => {
addChildrenMarkedToKeep,
addMarkedToDelete,
addMarkedToKeep,
hoveredId,
hoveredNode,
markedToDelete,
markedToKeep,
setHoveredId,
setHoveredNode,
setMarkedToDelete,
setMarkedToKeep,
};
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/utils/constants.ts
Expand Up @@ -62,3 +62,6 @@ export const MONTHS_NB = {

export const AVERAGE_MAIL_SIZE_IN_MO = 0.005;
export const AVERAGE_MAIL_SIZE_IN_KO = 5;

export const ECOLOGIC_IMPACT_FACTOR = 19;
export const ECOLOGIC_TRAIN_FACTOR = 578;
7 changes: 4 additions & 3 deletions src/renderer/utils/dashboard-recap.ts
Expand Up @@ -5,6 +5,7 @@ import type {
PstFolder,
} from "@common/modules/pst-extractor/type";
import { isPstFolder } from "@common/modules/pst-extractor/type";
import { toOneDecimalsFloat } from "@common/utils";

export const getPstTotalReceivedMails = (
extractTables: PstExtractTables | undefined
Expand Down Expand Up @@ -89,12 +90,12 @@ export const getPstTotalMails = (
export const getPstMailsPercentage = (
current: number,
total: Map<string, PstEmail[]> | undefined
): string => {
): number => {
const totalMails = getPstTotalMails(total);
if (totalMails) {
return ((current / totalMails) * 100).toFixed(1);
return toOneDecimalsFloat((current / totalMails) * 100);
}
return "0";
return 0;
};

interface FolderListItem {
Expand Down

0 comments on commit 2e84d68

Please sign in to comment.