Skip to content

Commit

Permalink
♻️ Flatten context a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
leeandher committed Feb 25, 2025
1 parent 36dfef6 commit 52cc442
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 82 deletions.
16 changes: 3 additions & 13 deletions static/app/components/tours/issueDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,10 @@ export function useIssueDetailsTourReducer(
}

export const IssueDetailsTourContext = createContext<TourContextType<IssueDetailsTour>>({
tour: {
currentStep: null,
isAvailable: false,
orderedStepIds: ORDERED_ISSUE_DETAILS_TOUR_STEP_IDS,
},
currentStep: null,
isAvailable: false,
orderedStepIds: ORDERED_ISSUE_DETAILS_TOUR_STEP_IDS,
dispatch: () => {},
registry: {
[IssueDetailsTour.ISSUE_DETAILS_AGGREGATES]: null,
[IssueDetailsTour.ISSUE_DETAILS_FILTERS]: null,
[IssueDetailsTour.ISSUE_DETAILS_EVENT_DETAILS]: null,
[IssueDetailsTour.ISSUE_DETAILS_NAVIGATION]: null,
[IssueDetailsTour.ISSUE_DETAILS_WORKFLOWS]: null,
[IssueDetailsTour.ISSUE_DETAILS_SIDEBAR]: null,
},
});

export function useIssueDetailsTour(): TourContextType<IssueDetailsTour> {
Expand Down
112 changes: 49 additions & 63 deletions static/app/components/tours/styles.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ClassNames, useTheme} from '@emotion/react';
import {useTheme} from '@emotion/react';
import styled from '@emotion/styled';

import {Button} from 'sentry/components/button';
Expand All @@ -15,9 +15,8 @@ import {space} from 'sentry/styles/space';
import type {UseHoverOverlayProps} from 'sentry/utils/useHoverOverlay';

export function TourBlurContainer({children}: {children: React.ReactNode}) {
const {tour} = useIssueDetailsTour();
const isTourActive = tour.currentStep !== null;

const {currentStep} = useIssueDetailsTour();
const isTourActive = currentStep !== null;
return (
<BlurContainer>
{children}
Expand All @@ -40,68 +39,55 @@ export function TourElement<T extends TourEnumType>({
position,
}: TourElementProps<T>) {
const theme = useTheme();
const {tour, dispatch} = tourContext;
const {orderedStepIds} = tour;
const currentStepIndex = tour.currentStep
? orderedStepIds.indexOf(tour.currentStep.id)
: -1;
const {currentStep, orderedStepIds, dispatch} = tourContext;
const currentStepIndex = currentStep ? orderedStepIds.indexOf(currentStep.id) : -1;
const hasPreviousStep = currentStepIndex > 0;
const hasNextStep = currentStepIndex < orderedStepIds.length - 1;
return (
<ClassNames>
{({css}) => (
<TourHovercard
skipWrapper
forceVisible
tipColor={'black'}
bodyClassName={css`
padding: ${space(1.5)} ${space(2)};
`}
position={position}
body={
<TourContent>
<TopRow>
<div>
{currentStepIndex + 1}/{orderedStepIds.length}
</div>
<div>
<TourCloseButton
onClick={() => dispatch({type: 'END_TOUR'})}
icon={<IconClose style={{color: theme.inverted.textColor}} />}
aria-label={t('Close')}
borderless
size="sm"
/>
</div>
</TopRow>
<TitleRow>{step.title}</TitleRow>
<DescriptionRow>{step.description}</DescriptionRow>
<ActionRow>
{hasPreviousStep && (
<ActionButton
size="xs"
onClick={() => dispatch({type: 'PREVIOUS_STEP'})}
>
{t('Previous')}
</ActionButton>
)}
{hasNextStep ? (
<ActionButton size="xs" onClick={() => dispatch({type: 'NEXT_STEP'})}>
{t('Next')}
</ActionButton>
) : (
<ActionButton size="xs" onClick={() => dispatch({type: 'END_TOUR'})}>
{t('Finish tour')}
</ActionButton>
)}
</ActionRow>
</TourContent>
}
>
<TourWrapper>{children}</TourWrapper>
</TourHovercard>
)}
</ClassNames>
<TourHovercard
skipWrapper
forceVisible
tipColor={'black'}
position={position}
body={
<TourContent>
<TopRow>
<div>
{currentStepIndex + 1}/{orderedStepIds.length}
</div>
<div>
<TourCloseButton
onClick={() => dispatch({type: 'END_TOUR'})}
icon={<IconClose style={{color: theme.inverted.textColor}} />}
aria-label={t('Close')}
borderless
size="sm"
/>
</div>
</TopRow>
<TitleRow>{step.title}</TitleRow>
<DescriptionRow>{step.description}</DescriptionRow>
<ActionRow>
{hasPreviousStep && (
<ActionButton size="xs" onClick={() => dispatch({type: 'PREVIOUS_STEP'})}>
{t('Previous')}
</ActionButton>
)}
{hasNextStep ? (
<ActionButton size="xs" onClick={() => dispatch({type: 'NEXT_STEP'})}>
{t('Next')}
</ActionButton>
) : (
<ActionButton size="xs" onClick={() => dispatch({type: 'END_TOUR'})}>
{t('Finish tour')}
</ActionButton>
)}
</ActionRow>
</TourContent>
}
>
<TourWrapper>{children}</TourWrapper>
</TourHovercard>
);
}

Expand Down
10 changes: 4 additions & 6 deletions static/app/components/tours/tourContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,11 @@ export function useTourReducer<T extends TourEnumType>({

const [tour, dispatch] = useReducer(reducer, initState);

return {tour, registry, dispatch};
return {...tour, dispatch};
}

export interface TourContextType<T extends TourEnumType> {
export interface TourContextType<T extends TourEnumType> extends TourState<T> {
dispatch: Dispatch<TourAction<T>>;
registry: TourRegistry<T>;
tour: TourState<T>;
}

type TourRegistry<T extends TourEnumType> = {
Expand Down Expand Up @@ -219,14 +217,14 @@ export function useRegisterTourStep<T extends TourEnumType>({
);

// Use the dispatch and tour state from the props context
const {tour, dispatch} = tourContext;
const {currentStep, dispatch} = tourContext;

// Register the step in the registry
useEffect(() => {
dispatch({type: 'REGISTER_STEP', step});
}, [step, dispatch]);

const isActiveStep = tour?.currentStep?.id === step.id;
const isActiveStep = currentStep?.id === step.id;

// Return a callback that renders the element wrapped if the tour is active, registered and matches the step
const element = isActiveStep ? (
Expand Down

0 comments on commit 52cc442

Please sign in to comment.