Skip to content

Commit 559d59c

Browse files
committed
add activatable status indicator
1 parent 3a56f71 commit 559d59c

6 files changed

Lines changed: 79 additions & 12 deletions

File tree

packages/client/src/clients/guide/client.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,13 @@ const predicate = (
217217
return false;
218218
}
219219

220+
return checkActivatable(guide, location);
221+
};
222+
223+
export const checkActivatable = (
224+
guide: KnockGuide,
225+
location: string | undefined,
226+
) => {
220227
const url = location ? newUrl(location) : undefined;
221228

222229
const urlRules = guide.activation_url_rules || [];

packages/client/src/clients/guide/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
export { KnockGuideClient, DEBUG_QUERY_PARAMS } from "./client";
1+
export {
2+
KnockGuideClient,
3+
DEBUG_QUERY_PARAMS,
4+
checkActivatable,
5+
} from "./client";
26
export type {
37
KnockGuide,
48
KnockGuideStep,

packages/react/src/modules/guide/components/Toolbar/V2/GuideRow.tsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { Button } from "@telegraph/button";
2-
import { Stack } from "@telegraph/layout";
2+
import { Box, Stack } from "@telegraph/layout";
33
import { Tag } from "@telegraph/tag";
44
import { Tooltip } from "@telegraph/tooltip";
55
import { Text } from "@telegraph/typography";
6-
import { CheckCircle2, CircleDashed, Eye, UserCircle2 } from "lucide-react";
6+
import {
7+
CheckCircle2,
8+
CircleDashed,
9+
Eye,
10+
LocateFixed,
11+
UserCircle2,
12+
} from "lucide-react";
713
import * as React from "react";
814

915
import { GuideHoverCard } from "./GuideHoverCard";
@@ -39,6 +45,27 @@ export const GuideRow = ({ guide, orderIndex }: Props) => {
3945
</Stack>
4046

4147
<Stack justify="flex-end">
48+
{guide.__typename === "Guide" && (
49+
<Stack gap="1">
50+
<Tooltip
51+
label="Current location does not match the activation conditions"
52+
enabled={!guide.inspection.activatable.status}
53+
>
54+
<Button
55+
px="1"
56+
size="1"
57+
variant="soft"
58+
color={guide.inspection.activatable.status ? "green" : "red"}
59+
leadingIcon={{ icon: LocateFixed, alt: "Target" }}
60+
/>
61+
</Tooltip>
62+
</Stack>
63+
)}
64+
{guide.__typename === "Guide" && (
65+
<Stack px="1" align="center">
66+
<Box h="3" borderLeft="px" borderColor="gray-6" />
67+
</Stack>
68+
)}
4269
<Stack gap="1">
4370
{guide.__typename === "Guide" && (
4471
<>
@@ -49,6 +76,7 @@ export const GuideRow = ({ guide, orderIndex }: Props) => {
4976
: guide.inspection.targetable.message
5077
}
5178
// enabled={!guide.inspection.targetable.status}
79+
enabled={!guide.inspection.targetable.status}
5280
>
5381
<Button
5482
px="1"

packages/react/src/modules/guide/components/Toolbar/V2/GuidesListDisplaySelect.tsx

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@ export const GuidesListDisplaySelect = ({ value, onChange }: Props) => {
2222
style: { zIndex: MAX_Z_INDEX },
2323
}}
2424
>
25-
{/*
26-
<Select.Option size="1" value="current-page">
27-
Displayable on current page
28-
</Select.Option>
29-
*/}
25+
<Select.Option size="1" value="current-page">
26+
Displayable on current page
27+
</Select.Option>
3028
<Select.Option size="1" value="all-eligible">
3129
All eligible guides for user
3230
</Select.Option>

packages/react/src/modules/guide/components/Toolbar/V2/V2.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ import {
1616
import { detectToolbarParam } from "./helpers";
1717
import {
1818
checkEligible,
19+
checkUsable,
1920
useInspectGuideClientStore,
2021
} from "./useInspectGuideClientStore";
2122

2223
export const V2 = () => {
2324
const { client } = useGuideContext();
2425

2526
const [guidesListDisplayed, setGuidesListDisplayed] =
26-
React.useState<DisplayOption>("all-eligible");
27+
React.useState<DisplayOption>("current-page");
2728

2829
const [isVisible, setIsVisible] = React.useState(detectToolbarParam());
2930
const [isCollapsed, setIsCollapsed] = React.useState(true);
@@ -104,6 +105,13 @@ export const V2 = () => {
104105
<Box w="full">
105106
{data.error && <Box>{data.error}</Box>}
106107
{data.guides.map((guide, idx) => {
108+
if (
109+
guidesListDisplayed === "current-page" &&
110+
!checkUsable(guide)
111+
) {
112+
return null;
113+
}
114+
107115
if (
108116
guidesListDisplayed === "all-eligible" &&
109117
!checkEligible(guide)

packages/react/src/modules/guide/components/Toolbar/V2/useInspectGuideClientStore.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
KnockGuide,
33
KnockGuideClientStoreState,
44
KnockGuideIneligibilityMarker,
5+
checkActivatable,
56
} from "@knocklabs/client";
67
import { useGuideContext, useStore } from "@knocklabs/react-core";
78

@@ -19,6 +20,10 @@ type TargetableStatusFalse = {
1920
};
2021
type TargetableStatus = TargetableStatusTrue | TargetableStatusFalse;
2122

23+
type ActivatableStatus = {
24+
status: boolean;
25+
};
26+
2227
type ArchivedStatus = {
2328
status: boolean;
2429
};
@@ -28,6 +33,7 @@ export type InspectedGuide = KnockGuide & {
2833
// true status = good
2934
active: ActiveStatus;
3035
targetable: TargetableStatus;
36+
activatable: ActivatableStatus;
3137

3238
// false status = good
3339
archived: ArchivedStatus;
@@ -43,6 +49,14 @@ export const checkEligible = (guide: InspectedGuide | MissingGuide) => {
4349
return true;
4450
};
4551

52+
export const checkUsable = (guide: InspectedGuide | MissingGuide) => {
53+
if (guide.__typename === "MissingGuide") return false;
54+
if (!checkEligible(guide)) return false;
55+
if (!guide.inspection.activatable.status) return false;
56+
57+
return true;
58+
};
59+
4660
// Exists and ordered in control but absent in switchboard (therefore not
4761
// included in the api response), which implies a newly created guide that has
4862
// never been published to switchboard.
@@ -87,13 +101,15 @@ const toArchivedStatus = (
87101

88102
const inspectGuide = (
89103
guide: KnockGuide,
90-
ineligibleGuides: KnockGuideClientStoreState["ineligibleGuides"],
104+
{ ineligibleGuides, location }: StoreStateSnapshot,
105+
// ineligibleGuides: KnockGuideClientStoreState["ineligibleGuides"],
91106
): InspectedGuide => {
92107
const marker = ineligibleGuides[guide.key];
93108

94109
const inspection: InspectedGuide["inspection"] = {
95110
active: { status: guide.active },
96111
targetable: marker ? toTargetableStatus(marker) : { status: true },
112+
activatable: { status: checkActivatable(guide, location) },
97113
archived: marker ? toArchivedStatus(marker) : { status: false },
98114
};
99115

@@ -111,12 +127,18 @@ const newMissingGuide = (key: KnockGuide["key"]) =>
111127
bypass_global_group_limit: false,
112128
}) as MissingGuide;
113129

130+
type StoreStateSnapshot = Pick<
131+
KnockGuideClientStoreState,
132+
"location" | "guides" | "guideGroups" | "ineligibleGuides" | "debug"
133+
>;
134+
114135
export const useInspectGuideClientStore = (): InspectionResult | undefined => {
115136
const { client } = useGuideContext();
116137

117138
// Extract a snapshot of the client store state for debugging.
118-
const snapshot = useStore(client.store, (state) => {
139+
const snapshot: StoreStateSnapshot = useStore(client.store, (state) => {
119140
return {
141+
location: state.location,
120142
guides: state.guides,
121143
guideGroups: state.guideGroups,
122144
ineligibleGuides: state.ineligibleGuides,
@@ -146,7 +168,7 @@ export const useInspectGuideClientStore = (): InspectionResult | undefined => {
146168
return newMissingGuide(guideKey);
147169
}
148170

149-
return inspectGuide(guide, snapshot.ineligibleGuides);
171+
return inspectGuide(guide, snapshot);
150172
});
151173

152174
return {

0 commit comments

Comments
 (0)