Skip to content

Commit

Permalink
Expand all toggle (#704)
Browse files Browse the repository at this point in the history
* expand all toggle

* update EventCollapseState to EventExpansionState
  • Loading branch information
Assem-Hafez authored Oct 31, 2024
1 parent 662a7f1 commit e76050b
Show file tree
Hide file tree
Showing 13 changed files with 459 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { renderHook, act } from '@/test-utils/rtl';

import useEventExpansionToggle from '../use-event-expansion-toggle';

describe('useEventExpansionToggle', () => {
const mockVisibleEvents = [
{ eventId: '1' },
{ eventId: '2' },
{ eventId: '3' },
];

it('should initialize with provided initialState as true (all events expanded)', () => {
const { result } = renderHook(() =>
useEventExpansionToggle({
initialState: true,
visibleEvents: mockVisibleEvents,
})
);
expect(result.current.expandedEvents).toBe(true);
});

it('should initialize with provided initialState as an object with specific events expanded', () => {
const { result } = renderHook(() =>
useEventExpansionToggle({
initialState: { '1': true, '2': false },
visibleEvents: mockVisibleEvents,
})
);
expect(result.current.expandedEvents).toEqual({ '1': true, '2': false });
});

it('should toggle all events expansion state', () => {
const { result } = renderHook(() =>
useEventExpansionToggle({
initialState: { '1': true, '2': false },
visibleEvents: mockVisibleEvents,
})
);

act(() => {
result.current.toggleIsExpandAllEvents();
});
expect(result.current.expandedEvents).toBe(true);

act(() => {
result.current.toggleIsExpandAllEvents();
});
expect(result.current.expandedEvents).toEqual({});
});

it('should expand a specific event when toggled', () => {
const { result } = renderHook(() =>
useEventExpansionToggle({
initialState: {},
visibleEvents: mockVisibleEvents,
})
);

act(() => {
result.current.toggleIsEventExpanded('1');
});
expect(result.current.expandedEvents).toEqual({ '1': true });
});

it('should collapse a specific event when toggled if already expanded', () => {
const { result } = renderHook(() =>
useEventExpansionToggle({
initialState: { '1': true },
visibleEvents: mockVisibleEvents,
})
);

act(() => {
result.current.toggleIsEventExpanded('1');
});
expect(result.current.expandedEvents).toEqual({});
});

it('should collapse only the toggled event when all events are expanded', () => {
const { result } = renderHook(() =>
useEventExpansionToggle({
initialState: true,
visibleEvents: mockVisibleEvents,
})
);

act(() => {
result.current.toggleIsEventExpanded('1');
});

expect(result.current.expandedEvents).toEqual({
'2': true,
'3': true,
});
});

it('should expand all events when each event has been individually expanded', () => {
const { result } = renderHook(() =>
useEventExpansionToggle({
initialState: {},
visibleEvents: mockVisibleEvents,
})
);

act(() => {
result.current.toggleIsEventExpanded('1');
result.current.toggleIsEventExpanded('2');
result.current.toggleIsEventExpanded('3');
});

expect(result.current.expandedEvents).toBe(true);
});

it('should check if an event is expanded using getIsEventExpanded', () => {
const { result } = renderHook(() =>
useEventExpansionToggle({
initialState: { '1': true, '2': false },
visibleEvents: mockVisibleEvents,
})
);

expect(result.current.getIsEventExpanded('1')).toBe(true);
expect(result.current.getIsEventExpanded('2')).toBe(false);
expect(result.current.getIsEventExpanded('3')).toBe(false);
});
});
88 changes: 88 additions & 0 deletions src/views/workflow-history/hooks/use-event-expansion-toggle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { useCallback, useState } from 'react';

import omit from 'lodash/omit';

import { type HistoryEvent } from '@/__generated__/proto-ts/uber/cadence/api/v1/HistoryEvent';

import {
type EventExpansionState,
type GetIsEventExpanded,
type ToggleIsEventExpanded,
type ToggleIsExpandAllEvents,
} from './use-event-expansion-toggle.types';

export default function useEventExpansionToggle({
initialState = {},
visibleEvents,
}: {
initialState?: EventExpansionState;
visibleEvents: Pick<HistoryEvent, 'eventId'>[];
}) {
const [expandedEvents, setExpandedEvents] =
useState<EventExpansionState>(initialState);

const isExpandAllEvents = expandedEvents === true;
const toggleIsExpandAllEvents = useCallback<ToggleIsExpandAllEvents>(() => {
setExpandedEvents((prev) => {
if (prev === true) {
return {};
}

return true;
});
}, []);

const getIsEventExpanded = useCallback<GetIsEventExpanded>(
(eventId: string) => {
if (expandedEvents === true) {
return true;
}

return Boolean(expandedEvents[eventId]);
},
[expandedEvents]
);

const toggleIsEventExpanded = useCallback<ToggleIsEventExpanded>(
(eventId: string) => {
setExpandedEvents((prev) => {
let newState: Record<string, boolean>;
if (prev === true) {
const retainedExpansion = visibleEvents.reduce(
(result, { eventId }) => {
result[eventId] = true;
return result;
},
{} as Record<string, boolean>
);
newState = omit(retainedExpansion, eventId);
} else {
if (prev[eventId] === true) {
newState = omit(prev, eventId);
} else {
newState = {
...prev,
[eventId]: true,
};
}
}
if (visibleEvents.every(({ eventId }) => newState[eventId])) {
return true;
}
return newState;
});
},
[visibleEvents]
);

return {
expandedEvents,
setExpandedEvents,

isExpandAllEvents,
toggleIsExpandAllEvents,

getIsEventExpanded,
toggleIsEventExpanded,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type EventExpansionState = Record<string, boolean> | true;

export type ToggleIsExpandAllEvents = () => void;

export type GetIsEventExpanded = (eventId: string) => boolean;

export type OnEventExpandToggle = (eventId: string) => void;

export type ToggleIsEventExpanded = (eventId: string) => void;
Loading

0 comments on commit e76050b

Please sign in to comment.