Commit e27b1857 authored by SHAWNA MONERO's avatar SHAWNA MONERO
Browse files

add time selector hooks

parent 991c5d70
Showing with 123 additions and 8 deletions
+123 -8
import * as React from "react";
import type { DashAction, DashState, TimeDataUpdate, TimelineAction, TimelineState } from "./types";
import type {
DashAction,
DashState,
TimeDataUpdate,
TimelineAction,
TimelineState,
TimeSelectorAction,
TimeSelectorState,
} from "./types";
// Contexts for project selector
export const ProjectSelectorStateContext = React.createContext<DashState | undefined>(undefined);
......@@ -14,6 +22,14 @@ export const TimelineDispatchContext = React.createContext<
((action: TimelineAction) => void) | undefined
>(undefined);
// Contexts for time selector
export const TimeSelectorStateContext = React.createContext<TimeSelectorState | undefined>(
undefined
);
export const TimeSelectorDispatchContext = React.createContext<
((action: TimeSelectorAction) => void) | undefined
>(undefined);
// project selector hooks
type useDashUpdaterReturn = {
updateSelected: (state: DashState) => void;
......@@ -65,3 +81,30 @@ export const useTimelineState = (): TimelineState => {
}
return value;
};
// timestamp selection hooks
type useTimeSelectorReturn = {
updateTimeSelection: (state: TimeSelectorState) => void;
};
// hook for writing
export const useTimeSelectorUpdater = (): useTimeSelectorReturn => {
const dispatch = React.useContext(TimeSelectorDispatchContext);
return {
updateTimeSelection: (state: TimeSelectorState) => {
dispatch && dispatch({ type: "UPDATE", payload: state });
},
};
};
// hook for reading
export const useTimeSelectorState = (): TimeSelectorState => {
const value = React.useContext<TimeSelectorState | undefined>(TimeSelectorStateContext);
if (!value) {
throw new Error(
"useTimeSelectorState was invoked outside of a valid context, check that it is a child of the TimeSelector component"
);
}
return value;
};
......@@ -8,19 +8,36 @@ import {
ProjectSelectorStateContext,
TimelineDispatchContext,
TimelineStateContext,
TimeSelectorDispatchContext,
TimeSelectorStateContext,
} from "./dash-hooks";
import ProjectSelector from "./project-selector";
import type { DashAction, DashState, TimelineAction, TimelineState } from "./types";
import type {
DashAction,
DashState,
TimelineAction,
TimelineState,
TimeSelectorAction,
TimeSelectorState,
} from "./types";
const initialState = {
// Default look back is 2 hours for time selector
const TWO_HOURS_MS = 7200000;
const initialState: DashState = {
selected: [],
projectData: {},
};
const initialTimelineState = {
const initialTimelineState: TimelineState = {
timeData: {},
};
const initialTimeSelectorState: TimeSelectorState = {
startTimeMillis: Date.now() - TWO_HOURS_MS,
endTimeMillis: Date.now(),
};
const CardContainer = styled.div({
display: "flex",
flex: 1,
......@@ -55,9 +72,32 @@ const timelineReducer = (state: TimelineState, action: TimelineAction): Timeline
}
};
const timeSelectorReducer = (
state: TimeSelectorState,
action: TimeSelectorAction
): TimeSelectorState => {
switch (action.type) {
case "UPDATE": {
if (
!_.isEqual(state.startTimeMillis, action.payload.startTimeMillis) ||
!_.isEqual(state.endTimeMillis, action.payload.endTimeMillis)
) {
return action.payload;
}
return state;
}
default:
throw new Error("not implemented (should be unreachable)");
}
};
const Dash = ({ children }) => {
const [state, dispatch] = React.useReducer(dashReducer, initialState);
const [timelineState, timelineDispatch] = React.useReducer(timelineReducer, initialTimelineState);
const [timeSelectorState, timeSelectorDispatch] = React.useReducer(
timeSelectorReducer,
initialTimeSelectorState
);
return (
<Box display="flex" flex={1} minHeight="100%" maxHeight="100%">
{/* TODO: Maybe in the future invert proj selector and timeline contexts */}
......@@ -65,8 +105,12 @@ const Dash = ({ children }) => {
<ProjectSelectorStateContext.Provider value={state}>
<TimelineDispatchContext.Provider value={timelineDispatch}>
<TimelineStateContext.Provider value={timelineState}>
<ProjectSelector />
<CardContainer>{children}</CardContainer>
<TimeSelectorDispatchContext.Provider value={timeSelectorDispatch}>
<TimeSelectorStateContext.Provider value={timeSelectorState}>
<ProjectSelector />
<CardContainer>{children}</CardContainer>
</TimeSelectorStateContext.Provider>
</TimeSelectorDispatchContext.Provider>
</TimelineStateContext.Provider>
</TimelineDispatchContext.Provider>
</ProjectSelectorStateContext.Provider>
......
......@@ -2,7 +2,13 @@ import type { BaseWorkflowProps, WorkflowConfiguration } from "@clutch-sh/core";
import Card from "./card";
import Dash from "./dash";
import { useDashState, useTimelineState, useTimelineUpdater } from "./dash-hooks";
import {
useDashState,
useTimelineState,
useTimelineUpdater,
useTimeSelectorState,
useTimeSelectorUpdater,
} from "./dash-hooks";
export interface WorkflowProps extends BaseWorkflowProps {}
......@@ -34,5 +40,14 @@ export type {
TimeData,
TimeDataUpdate,
ProjectToPointsMap,
TimeSelectorState,
} from "./types";
export { Card, Dash, useDashState, useTimelineState, useTimelineUpdater };
export {
Card,
Dash,
useDashState,
useTimelineState,
useTimelineUpdater,
useTimeSelectorState,
useTimeSelectorUpdater,
};
......@@ -142,5 +142,18 @@ export interface TimelineAction {
type: TimelineActionKindUpdate;
payload: TimeDataUpdate;
}
export interface TimeSelectorState {
/** The start of the time window the user has chosen */
startTimeMillis: number;
/** The end of time window the user has chosen */
endTimeMillis: number;
}
export type TimeSelectorActionUpdate = "UPDATE";
export interface TimeSelectorAction {
type: TimeSelectorActionUpdate;
payload: TimeSelectorState;
}
export { isGroupState, isProjectState, isGlobalProjectState };
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment