diff --git a/.tool-versions b/.tool-versions index e871cd693..d173c8890 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -nodejs 24.12.0 +nodejs 24.13.0 yarn 1.22.22 diff --git a/examples/guide-example/src/App.tsx b/examples/guide-example/src/App.tsx index ab59a88ce..9d3204fe8 100644 --- a/examples/guide-example/src/App.tsx +++ b/examples/guide-example/src/App.tsx @@ -65,6 +65,7 @@ function App() { readyToTarget={true} listenForUpdates={true} colorMode={colorMode} + toolbar="v2" >

Knock In-App Guide Example

diff --git a/package.json b/package.json index 6c08dae8e..d08068038 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,6 @@ "vitest": "^3.1.1" }, "engines": { - "node": ">=24.10.0" + "node": ">=24.13.0" } } diff --git a/packages/client/src/clients/guide/client.ts b/packages/client/src/clients/guide/client.ts index f3ee847e9..b83b8bdc2 100644 --- a/packages/client/src/clients/guide/client.ts +++ b/packages/client/src/clients/guide/client.ts @@ -295,6 +295,7 @@ export class KnockGuideClient { guideGroups: [], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location, @@ -376,7 +377,12 @@ export class KnockGuideClient { >(this.channelId, queryParams); queryStatus = { status: "ok" }; - const { entries, guide_groups: groups, guide_group_display_logs } = data; + const { + entries, + guide_groups: groups, + guide_group_display_logs, + ineligible_guides, + } = data; this.knock.log("[Guide] Loading fetched guides"); this.store.setState((state) => ({ @@ -384,6 +390,7 @@ export class KnockGuideClient { guideGroups: groups?.length > 0 ? groups : [mockDefaultGroup(entries)], guideGroupDisplayLogs: guide_group_display_logs || {}, guides: byKey(entries.map((g) => this.localCopy(g))), + ineligibleGuides: byKey(ineligible_guides), queries: { ...state.queries, [queryKey]: queryStatus }, })); } catch (e) { diff --git a/packages/client/src/clients/guide/types.ts b/packages/client/src/clients/guide/types.ts index f7112713b..9f52bd92e 100644 --- a/packages/client/src/clients/guide/types.ts +++ b/packages/client/src/clients/guide/types.ts @@ -63,6 +63,13 @@ export interface GuideGroupData { updated_at: string; } +export type GuideIneligibilityData = { + __typename: "GuideIneligibilityMarker"; + key: KnockGuide["key"]; + reason: string; + message: string; +}; + export type GetGuidesQueryParams = { data?: string; tenant?: string; @@ -74,6 +81,7 @@ export type GetGuidesResponse = { entries: GuideData[]; guide_groups: GuideGroupData[]; guide_group_display_logs: Record; + ineligible_guides: GuideIneligibilityData[]; }; // @@ -200,6 +208,10 @@ export type StoreState = { guideGroups: GuideGroupData[]; guideGroupDisplayLogs: Record; guides: Record; + ineligibleGuides: Record< + GuideIneligibilityData["key"], + GuideIneligibilityData + >; previewGuides: Record; queries: Record; location: string | undefined; diff --git a/packages/client/test/clients/guide/guide.test.ts b/packages/client/test/clients/guide/guide.test.ts index 999c93846..feb5afd7b 100644 --- a/packages/client/test/clients/guide/guide.test.ts +++ b/packages/client/test/clients/guide/guide.test.ts @@ -24,6 +24,7 @@ const mockStore = { guideGroups: [], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -45,6 +46,7 @@ const mockStore = { guideGroups: [], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -94,6 +96,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -104,6 +107,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -156,6 +160,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -184,6 +189,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: "https://example.com", @@ -200,6 +206,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -593,6 +600,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: { [mockGuide.key]: mockGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -623,6 +631,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: { [mockGuide.key]: mockGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -654,6 +663,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: { [mockGuide.key]: mockGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -689,6 +699,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: { [mockGuide.key]: mockGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -744,6 +755,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: { [unthrottledGuide.key]: unthrottledGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -798,6 +810,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: { [throttledGuide.key]: throttledGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -858,6 +871,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: { [unthrottledGuide.key]: unthrottledGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1027,6 +1041,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1048,6 +1063,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1068,6 +1084,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1088,6 +1105,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: "https://example.com/dashboard", @@ -1107,6 +1125,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: "https://example.com/settings", @@ -1145,8 +1164,9 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com/dashboard", counter: 0, + ineligibleGuides: {}, previewGuides: {}, - debug: { forcedGuideKey: null }, + debug: { forcedGuideKey: null, previewSessionId: null }, }; const client = new KnockGuideClient(mockKnock, channelId); @@ -1180,8 +1200,9 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com/dashboard", counter: 0, + ineligibleGuides: {}, previewGuides: {}, - debug: { forcedGuideKey: null }, + debug: { forcedGuideKey: null, previewSessionId: null }, }; const client = new KnockGuideClient(mockKnock, channelId); @@ -1215,8 +1236,9 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com/settings", counter: 0, + ineligibleGuides: {}, previewGuides: {}, - debug: { forcedGuideKey: null }, + debug: { forcedGuideKey: null, previewSessionId: null }, }; const client = new KnockGuideClient(mockKnock, channelId); @@ -1250,8 +1272,9 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com/user/settings", counter: 0, + ineligibleGuides: {}, previewGuides: {}, - debug: { forcedGuideKey: null }, + debug: { forcedGuideKey: null, previewSessionId: null }, }; const client = new KnockGuideClient(mockKnock, channelId); @@ -1291,8 +1314,9 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com/admin/settings", counter: 0, + ineligibleGuides: {}, previewGuides: {}, - debug: { forcedGuideKey: null }, + debug: { forcedGuideKey: null, previewSessionId: null }, }; const client = new KnockGuideClient(mockKnock, channelId); @@ -1335,8 +1359,9 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com/dashboard", counter: 0, + ineligibleGuides: {}, previewGuides: {}, - debug: { forcedGuideKey: null }, + debug: { forcedGuideKey: null, previewSessionId: null }, }; const client = new KnockGuideClient(mockKnock, channelId); @@ -1370,8 +1395,9 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com/dashboard", counter: 0, + ineligibleGuides: {}, previewGuides: {}, - debug: { forcedGuideKey: null }, + debug: { forcedGuideKey: null, previewSessionId: null }, }; const client = new KnockGuideClient(mockKnock, channelId); @@ -1405,8 +1431,9 @@ describe("KnockGuideClient", () => { queries: {}, location: "https://example.com/dashboard", counter: 0, + ineligibleGuides: {}, previewGuides: {}, - debug: { forcedGuideKey: null }, + debug: { forcedGuideKey: null, previewSessionId: null }, }; const client = new KnockGuideClient(mockKnock, channelId); @@ -1445,6 +1472,7 @@ describe("KnockGuideClient", () => { [g2.key]: g2, [g3.key]: g3, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: "https://example.com/settings", @@ -1463,6 +1491,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1493,6 +1522,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1571,6 +1601,7 @@ describe("KnockGuideClient", () => { ...mockGuides, [mockGuideFour.key]: mockGuideFour, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1652,6 +1683,7 @@ describe("KnockGuideClient", () => { ], }, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1688,6 +1720,7 @@ describe("KnockGuideClient", () => { ...mockGuides, [mockGuideThree.key]: archivedGuide, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1728,6 +1761,7 @@ describe("KnockGuideClient", () => { ...mockGuides, [mockGuideTwo.key]: undefined as unknown as KnockGuide, }, + ineligibleGuides: {}, previewGuides: { [mockGuideTwo.key]: previewGuide, }, @@ -1774,6 +1808,7 @@ describe("KnockGuideClient", () => { queries: {}, location: undefined, counter: 0, + ineligibleGuides: {}, debug: { forcedGuideKey: mockGuideTwo.key, preview_session_id: "test-session-id", @@ -1810,6 +1845,7 @@ describe("KnockGuideClient", () => { queries: {}, location: undefined, counter: 0, + ineligibleGuides: {}, debug: { forcedGuideKey: mockGuideTwo.key, preview_session_id: "test-session-id", @@ -1836,6 +1872,7 @@ describe("KnockGuideClient", () => { default: new Date().toISOString(), }, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1877,6 +1914,7 @@ describe("KnockGuideClient", () => { bypass_global_group_limit: true, }, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -1902,6 +1940,7 @@ describe("KnockGuideClient", () => { default: new Date().toISOString(), // Throttle window started now }, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2015,6 +2054,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2085,6 +2125,7 @@ describe("KnockGuideClient", () => { ], }, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2105,6 +2146,7 @@ describe("KnockGuideClient", () => { guideGroups: [mockDefaultGroup], guideGroupDisplayLogs: {}, guides: {}, + ineligibleGuides: {}, previewGuides: { [mockGuideTwo.key]: mockGuideTwo, }, @@ -2136,6 +2178,7 @@ describe("KnockGuideClient", () => { active: false, }, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2166,6 +2209,7 @@ describe("KnockGuideClient", () => { default: new Date().toISOString(), // Throttle window started now }, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2200,6 +2244,7 @@ describe("KnockGuideClient", () => { ...mockGuides, [mockGuideTwo.key]: mockGuideWithBypass, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2228,6 +2273,7 @@ describe("KnockGuideClient", () => { default: new Date().toISOString(), // Throttle window started now }, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2266,6 +2312,7 @@ describe("KnockGuideClient", () => { default: tenMinutesAgo, }, guides: mockGuides, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2342,6 +2389,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: { [existingGuide.key]: existingGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2396,6 +2444,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: { [existingGuide.key]: existingGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2442,6 +2491,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: { [existingGuide.key]: existingGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2535,6 +2585,7 @@ describe("KnockGuideClient", () => { [mockGuideOne.key]: mockGuideOne, [mockGuideTwo.key]: mockGuideTwo, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2591,6 +2642,7 @@ describe("KnockGuideClient", () => { [mockGuideOne.key]: mockGuideOne, [mockGuideTwo.key]: mockGuideTwo, }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2860,6 +2912,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: { [mockGuide.key]: mockGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -2912,6 +2965,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: { [mockGuide.key]: mockGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, @@ -3009,6 +3063,7 @@ describe("KnockGuideClient", () => { guideGroups: [], guideGroupDisplayLogs: {}, guides: { [mockGuide.key]: mockGuide }, + ineligibleGuides: {}, previewGuides: {}, queries: {}, location: undefined, diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 80214ade0..97ee3fcfa 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -43,7 +43,6 @@ export { Card, CardView, KnockGuideProvider, - GuideToolbar as KnockGuideToolbar, Modal, ModalView, } from "./modules/guide"; diff --git a/packages/react/src/modules/guide/components/GuideToolbar/index.ts b/packages/react/src/modules/guide/components/GuideToolbar/index.ts deleted file mode 100644 index 54c13648f..000000000 --- a/packages/react/src/modules/guide/components/GuideToolbar/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { GuideToolbar } from "./GuideToolbar"; diff --git a/packages/react/src/modules/guide/components/Toolbar/KnockButton.tsx b/packages/react/src/modules/guide/components/Toolbar/KnockButton.tsx new file mode 100644 index 000000000..93ae8e55a --- /dev/null +++ b/packages/react/src/modules/guide/components/Toolbar/KnockButton.tsx @@ -0,0 +1,51 @@ +import { Button } from "@telegraph/button"; + +import { MAX_Z_INDEX } from "./helpers"; +import "./styles.css"; + +type Props = { + onClick: () => void; +}; + +export const KnockButton = ({ onClick }: Props) => { + return ( + + ); +}; diff --git a/packages/react/src/modules/guide/components/GuideToolbar/GuideToolbar.tsx b/packages/react/src/modules/guide/components/Toolbar/V1.tsx similarity index 58% rename from packages/react/src/modules/guide/components/GuideToolbar/GuideToolbar.tsx rename to packages/react/src/modules/guide/components/Toolbar/V1.tsx index cb6d3989f..f0bc299aa 100644 --- a/packages/react/src/modules/guide/components/GuideToolbar/GuideToolbar.tsx +++ b/packages/react/src/modules/guide/components/Toolbar/V1.tsx @@ -6,13 +6,11 @@ import { Text } from "@telegraph/typography"; import { Minimize2, Undo2, Wrench } from "lucide-react"; import { useState } from "react"; +import { KnockButton } from "./KnockButton"; +import { MAX_Z_INDEX } from "./helpers"; import "./styles.css"; -// 'max' z index based on max value of a signed 32-bit int -// Ref: https://stackoverflow.com/questions/491052/minimum-and-maximum-value-of-z-index/25461690#25461690 -const MAX_Z_INDEX = 2147483647; - -export const GuideToolbar = () => { +export const V1 = () => { const [isCollapsed, setIsCollapsed] = useState(false); const { client } = useGuideContext(); @@ -31,46 +29,7 @@ export const GuideToolbar = () => { }; if (isCollapsed) { - return ( - - ); + return ; } return ( diff --git a/packages/react/src/modules/guide/components/Toolbar/V2.tsx b/packages/react/src/modules/guide/components/Toolbar/V2.tsx new file mode 100644 index 000000000..55265ab20 --- /dev/null +++ b/packages/react/src/modules/guide/components/Toolbar/V2.tsx @@ -0,0 +1,50 @@ +import { Button } from "@telegraph/button"; +import { Box, Stack } from "@telegraph/layout"; +import { Text } from "@telegraph/typography"; +import { Minimize2 } from "lucide-react"; +import { useState } from "react"; + +import { KnockButton } from "./KnockButton"; +import { MAX_Z_INDEX } from "./helpers"; +import "./styles.css"; + +export const V2 = () => { + const [isCollapsed, setIsCollapsed] = useState(true); + + return ( + + {isCollapsed ? ( + setIsCollapsed(false)} /> + ) : ( + + + + Toolbar v2 placeholder + + +