@confidencesystemsinc/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/components/badge.d.ts +54 -0
- package/dist/components/initiate-playbook-modal/InitiatePlaybookModal.d.ts +6 -0
- package/dist/components/playbook/confidence-playbook.d.ts +26 -0
- package/dist/components/playbook/playbook-header.d.ts +3 -0
- package/dist/components/playbook-button/ConfidencePlaybookButton.d.ts +8 -0
- package/dist/components/task/confidence-task.d.ts +17 -0
- package/dist/components/task/task-buttons.d.ts +5 -0
- package/dist/components/task/task-dropdown-badge.d.ts +18 -0
- package/dist/components/task/task-left-panel.d.ts +10 -0
- package/dist/components/task/task-status-badge.d.ts +9 -0
- package/dist/components/ui/button.d.ts +38 -0
- package/dist/components/ui/header.d.ts +1 -0
- package/dist/components/ui/input.d.ts +9 -0
- package/dist/components/ui/modal.d.ts +16 -0
- package/dist/constants/settings.constants.d.ts +2 -0
- package/dist/hooks/task-events/useCompleteTask.d.ts +99 -0
- package/dist/hooks/task-events/useStartTask.d.ts +99 -0
- package/dist/hooks/usePlaybook.d.ts +10 -0
- package/dist/hooks/usePlaybookActions.d.ts +6 -0
- package/dist/hooks/useTaskButtons.d.ts +17 -0
- package/dist/index.css +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/sdk.cjs +604 -0
- package/dist/sdk.js +12079 -0
- package/dist/services/complete-task.service.d.ts +4 -0
- package/dist/services/initiate-playbook.service.d.ts +11 -0
- package/dist/services/start-task.services.d.ts +4 -0
- package/dist/stories/initiate-playbook-modal.stories.d.ts +19 -0
- package/dist/stories/modal.stories.d.ts +28 -0
- package/dist/stories/playbook-container.stories.d.ts +55 -0
- package/dist/types/playbook.types.d.ts +20 -0
- package/dist/types/task.types.d.ts +18 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/vite.svg +1 -0
- package/package.json +66 -0
- package/src/App.css +2 -0
- package/src/components/badge.tsx +116 -0
- package/src/components/initiate-playbook-modal/InitiatePlaybookModal.tsx +53 -0
- package/src/components/playbook/confidence-playbook.tsx +193 -0
- package/src/components/playbook/playbook-header.tsx +13 -0
- package/src/components/playbook-button/ConfidencePlaybookButton.tsx +73 -0
- package/src/components/task/confidence-task.tsx +198 -0
- package/src/components/task/task-buttons.tsx +32 -0
- package/src/components/task/task-dropdown-badge.tsx +121 -0
- package/src/components/task/task-left-panel.tsx +60 -0
- package/src/components/task/task-status-badge.tsx +23 -0
- package/src/components/ui/button.tsx +269 -0
- package/src/components/ui/header.tsx +12 -0
- package/src/components/ui/input.tsx +39 -0
- package/src/components/ui/modal.tsx +88 -0
- package/src/constants/settings.constants.ts +2 -0
- package/src/hooks/task-events/useCompleteTask.ts +26 -0
- package/src/hooks/task-events/useStartTask.ts +29 -0
- package/src/hooks/usePlaybook.ts +48 -0
- package/src/hooks/usePlaybookActions.ts +69 -0
- package/src/hooks/useTaskButtons.ts +46 -0
- package/src/index.ts +6 -0
- package/src/services/complete-task.service.ts +21 -0
- package/src/services/initiate-playbook.service.ts +24 -0
- package/src/services/start-task.services.ts +23 -0
- package/src/stories/initiate-playbook-modal.stories.tsx +31 -0
- package/src/stories/modal.stories.tsx +50 -0
- package/src/stories/playbook-container.stories.tsx +79 -0
- package/src/types/playbook.types.ts +22 -0
- package/src/types/task.types.ts +20 -0
- package/src/utils/cn.ts +6 -0
- package/src/vite-env.d.ts +1 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { StoryObj } from '@storybook/react';
|
|
2
|
+
declare const meta: {
|
|
3
|
+
title: string;
|
|
4
|
+
component: ({ onConfirm, onClose, isOpen, title, }: {
|
|
5
|
+
onConfirm: (email: string) => void | Promise<void>;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
isOpen: boolean;
|
|
8
|
+
title?: string;
|
|
9
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: string;
|
|
12
|
+
};
|
|
13
|
+
tags: string[];
|
|
14
|
+
argTypes: {};
|
|
15
|
+
args: {};
|
|
16
|
+
};
|
|
17
|
+
export default meta;
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
export declare const Default: Story;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { StoryObj } from '@storybook/react';
|
|
2
|
+
declare const meta: {
|
|
3
|
+
title: string;
|
|
4
|
+
component: ({ isOpen, close, title, dismissOptions, confirmOptions, children, }: {
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
close: () => void;
|
|
7
|
+
title: string;
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
dismissOptions?: {
|
|
10
|
+
label: string;
|
|
11
|
+
onClick: () => void;
|
|
12
|
+
};
|
|
13
|
+
confirmOptions?: {
|
|
14
|
+
label: string;
|
|
15
|
+
onClick: () => void;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
};
|
|
18
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
parameters: {
|
|
20
|
+
layout: string;
|
|
21
|
+
};
|
|
22
|
+
tags: string[];
|
|
23
|
+
argTypes: {};
|
|
24
|
+
args: {};
|
|
25
|
+
};
|
|
26
|
+
export default meta;
|
|
27
|
+
type Story = StoryObj<typeof meta>;
|
|
28
|
+
export declare const Default: Story;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { StoryObj } from '@storybook/react';
|
|
2
|
+
import { TaskButton } from '../hooks/useTaskButtons';
|
|
3
|
+
declare const meta: {
|
|
4
|
+
title: string;
|
|
5
|
+
component: ({ playbook, viewMode, onTaskButtonClick, }: {
|
|
6
|
+
viewMode: "list" | "card";
|
|
7
|
+
playbook: import('../types/playbook.types').Playbook;
|
|
8
|
+
onTaskButtonClick: (btn: TaskButton, taskId: number) => void;
|
|
9
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: string;
|
|
12
|
+
};
|
|
13
|
+
tags: string[];
|
|
14
|
+
argTypes: {};
|
|
15
|
+
args: {
|
|
16
|
+
viewMode: "list";
|
|
17
|
+
playbook: {
|
|
18
|
+
playbookInstanceId: number;
|
|
19
|
+
playbookInstanceName: string;
|
|
20
|
+
playbookId: number;
|
|
21
|
+
type: string;
|
|
22
|
+
quickComplete: true;
|
|
23
|
+
autoExpandTask: true;
|
|
24
|
+
autoStart: false;
|
|
25
|
+
leadEmail: string;
|
|
26
|
+
workflowStatus: string;
|
|
27
|
+
numberofTasks: number;
|
|
28
|
+
tasks: ({
|
|
29
|
+
taskInstanceId: number;
|
|
30
|
+
taskId: number;
|
|
31
|
+
sequenceOrder: number;
|
|
32
|
+
workflowStatus: "Completed";
|
|
33
|
+
taskInstanceName: string;
|
|
34
|
+
taskStartTime: string;
|
|
35
|
+
taskCompletedTime: string;
|
|
36
|
+
imageRequired: number;
|
|
37
|
+
hasDescription: true;
|
|
38
|
+
} | {
|
|
39
|
+
taskInstanceId: number;
|
|
40
|
+
taskId: number;
|
|
41
|
+
sequenceOrder: number;
|
|
42
|
+
workflowStatus: "In progress";
|
|
43
|
+
taskInstanceName: string;
|
|
44
|
+
imageRequired: number;
|
|
45
|
+
hasDescription: true;
|
|
46
|
+
taskStartTime?: undefined;
|
|
47
|
+
taskCompletedTime?: undefined;
|
|
48
|
+
})[];
|
|
49
|
+
};
|
|
50
|
+
onTaskButtonClick: (btn: TaskButton, taskId: number) => void;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
export default meta;
|
|
54
|
+
type Story = StoryObj<typeof meta>;
|
|
55
|
+
export declare const Default: Story;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Task } from './task.types';
|
|
2
|
+
export interface Playbook {
|
|
3
|
+
playbookInstanceId: number;
|
|
4
|
+
playbookInstanceName: string;
|
|
5
|
+
playbookId: number;
|
|
6
|
+
type: string;
|
|
7
|
+
quickComplete: boolean;
|
|
8
|
+
autoExpandTask: boolean;
|
|
9
|
+
autoStart: boolean;
|
|
10
|
+
leadEmail: string;
|
|
11
|
+
workflowStatus: string;
|
|
12
|
+
numberofTasks: number;
|
|
13
|
+
nextTaskId?: number;
|
|
14
|
+
tasks: Task[];
|
|
15
|
+
}
|
|
16
|
+
export declare const PLAYBOOK_TYPES: {
|
|
17
|
+
readonly NON_SEQUENTIAL: "Non-Sequential";
|
|
18
|
+
readonly SEQUENTIAL: "Sequential";
|
|
19
|
+
};
|
|
20
|
+
export type PlaybookType = (typeof PLAYBOOK_TYPES)[keyof typeof PLAYBOOK_TYPES];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const TASK_STATUS: {
|
|
2
|
+
readonly OPEN: "Open";
|
|
3
|
+
readonly IN_PROGRESS: "In progress";
|
|
4
|
+
readonly IN_REVIEW: "In review";
|
|
5
|
+
readonly COMPLETED: "Completed";
|
|
6
|
+
};
|
|
7
|
+
export type TaskStatus = (typeof TASK_STATUS)[keyof typeof TASK_STATUS];
|
|
8
|
+
export interface Task {
|
|
9
|
+
taskInstanceId: number;
|
|
10
|
+
taskId: number;
|
|
11
|
+
sequenceOrder: number;
|
|
12
|
+
workflowStatus: TaskStatus;
|
|
13
|
+
taskInstanceName: string;
|
|
14
|
+
imageRequired: number;
|
|
15
|
+
hasDescription: boolean;
|
|
16
|
+
taskStartTime?: string;
|
|
17
|
+
taskCompletedTime?: string;
|
|
18
|
+
}
|
package/dist/vite.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@confidencesystemsinc/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/sdk.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc -b && vite build",
|
|
13
|
+
"lint": "eslint .",
|
|
14
|
+
"storybook": "storybook dev -p 6006",
|
|
15
|
+
"build-storybook": "storybook build"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@floating-ui/react": "^0.27.12",
|
|
19
|
+
"@headlessui/react": "^2.2.4",
|
|
20
|
+
"@headlessui/tailwindcss": "^0.2.2",
|
|
21
|
+
"@tanstack/react-query": "^5.76.1",
|
|
22
|
+
"@types/node": "^22.15.16",
|
|
23
|
+
"clsx": "^2.1.1",
|
|
24
|
+
"react": "^19.0.0",
|
|
25
|
+
"react-dom": "^19.0.0",
|
|
26
|
+
"tailwind-merge": "^3.2.0"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
|
30
|
+
"@fortawesome/free-brands-svg-icons": "^6.5.2",
|
|
31
|
+
"@fortawesome/free-regular-svg-icons": "^6.5.2",
|
|
32
|
+
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
|
33
|
+
"@fortawesome/react-fontawesome": "^0.1.18"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@chromatic-com/storybook": "^3",
|
|
37
|
+
"@storybook/addon-essentials": "^8.6.12",
|
|
38
|
+
"@storybook/addon-onboarding": "^8.6.12",
|
|
39
|
+
"@storybook/blocks": "^8.6.12",
|
|
40
|
+
"@storybook/experimental-addon-test": "^8.6.12",
|
|
41
|
+
"@storybook/react": "^8.6.12",
|
|
42
|
+
"@storybook/react-vite": "^8.6.12",
|
|
43
|
+
"@storybook/test": "^8.6.12",
|
|
44
|
+
"@tailwindcss/vite": "^4.1.4",
|
|
45
|
+
"@types/react": "^19.0.10",
|
|
46
|
+
"@types/react-dom": "^19.0.4",
|
|
47
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
48
|
+
"@vitest/browser": "^3.1.3",
|
|
49
|
+
"@vitest/coverage-v8": "^3.1.3",
|
|
50
|
+
"glob": "^11.0.2",
|
|
51
|
+
"globals": "^16.0.0",
|
|
52
|
+
"playwright": "^1.52.0",
|
|
53
|
+
"prettier": "^3.5.3",
|
|
54
|
+
"storybook": "^8.6.12",
|
|
55
|
+
"tailwindcss": "^4.1.4",
|
|
56
|
+
"typescript": "~5.7.2",
|
|
57
|
+
"typescript-eslint": "^8.31.0",
|
|
58
|
+
"vite": "^6.3.1",
|
|
59
|
+
"vite-plugin-dts": "^4.5.3",
|
|
60
|
+
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
61
|
+
"vitest": "^3.1.3"
|
|
62
|
+
},
|
|
63
|
+
"description": "This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.",
|
|
64
|
+
"author": "",
|
|
65
|
+
"license": "ISC"
|
|
66
|
+
}
|
package/src/App.css
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { ComponentPropsWithoutRef, useMemo } from "react";
|
|
2
|
+
import { twMerge } from "tailwind-merge";
|
|
3
|
+
|
|
4
|
+
export const BadgeSolid = {
|
|
5
|
+
white: "bg-white text-dark-300 border border-gray-300",
|
|
6
|
+
primary: "bg-primary-600",
|
|
7
|
+
secondary: "bg-secondary-500",
|
|
8
|
+
success: "bg-success-600",
|
|
9
|
+
info: "bg-info-500",
|
|
10
|
+
warning: "bg-warning-500 text-gray-800",
|
|
11
|
+
danger: "bg-danger-500",
|
|
12
|
+
steel: "bg-steel-500",
|
|
13
|
+
orange: "bg-orange-500",
|
|
14
|
+
purple: "bg-purple-500",
|
|
15
|
+
grayDark: "bg-gray-900",
|
|
16
|
+
grayLight: "bg-gray-100 text-gray-800",
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
export const BadgeOutline = {
|
|
20
|
+
white: "text-white border border-white",
|
|
21
|
+
primary: "text-primary-600 border border-primary-600",
|
|
22
|
+
secondary: "text-secondary-500 border border-secondary-500",
|
|
23
|
+
success: "text-success-600 border border-success-600",
|
|
24
|
+
info: "text-info-500 border border-info-500",
|
|
25
|
+
warning: "text-warning-500 border border-warning-500",
|
|
26
|
+
danger: "text-danger-500 border border-danger-500",
|
|
27
|
+
steel: "text-steel-500 border border-steel-500",
|
|
28
|
+
orange: "text-orange-500 border border-orange-500",
|
|
29
|
+
purple: "text-purple-500 border border-purple-500",
|
|
30
|
+
grayDark: "text-gray-700 border border-gray-700",
|
|
31
|
+
grayLight: "text-gray-500 border border-gray-100",
|
|
32
|
+
} as const;
|
|
33
|
+
|
|
34
|
+
const BadgeFontColor = {
|
|
35
|
+
white: "text-dark-300",
|
|
36
|
+
primary: "text-white",
|
|
37
|
+
secondary: "text-white",
|
|
38
|
+
success: "text-white",
|
|
39
|
+
info: "text-black",
|
|
40
|
+
warning: "text-gray-800",
|
|
41
|
+
danger: "text-white",
|
|
42
|
+
steel: "text-white",
|
|
43
|
+
orange: "text-black",
|
|
44
|
+
purple: "text-white",
|
|
45
|
+
grayDark: "text-white",
|
|
46
|
+
grayLight: "text-gray-800",
|
|
47
|
+
} as const;
|
|
48
|
+
|
|
49
|
+
export const BadgeRoundness = {
|
|
50
|
+
normal: "rounded",
|
|
51
|
+
pill: "rounded-pill",
|
|
52
|
+
} as const;
|
|
53
|
+
|
|
54
|
+
const BadgeSize = {
|
|
55
|
+
big: "h-[24px] leading-[24px] text-md px-1",
|
|
56
|
+
medium: "h-[22px] leading-[22px] text-sm px-[2px]",
|
|
57
|
+
small: "h-[18px] leading-[18px] text-xs px-[2px]",
|
|
58
|
+
} as const;
|
|
59
|
+
|
|
60
|
+
export interface BadgeProps extends ComponentPropsWithoutRef<"div"> {
|
|
61
|
+
category?: "solid" | "outline";
|
|
62
|
+
color?: keyof typeof BadgeSolid;
|
|
63
|
+
roundness?: keyof typeof BadgeRoundness;
|
|
64
|
+
size?: keyof typeof BadgeSize;
|
|
65
|
+
textClassName?: string;
|
|
66
|
+
children: React.ReactNode;
|
|
67
|
+
onClose?: () => void;
|
|
68
|
+
onArrowClick?: () => void;
|
|
69
|
+
className?: string;
|
|
70
|
+
onCustomIconClick?: () => void;
|
|
71
|
+
arrowTitle?: string;
|
|
72
|
+
closeTitle?: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const Badge = ({
|
|
76
|
+
category = "solid",
|
|
77
|
+
color = "primary",
|
|
78
|
+
roundness = "normal",
|
|
79
|
+
size = "medium",
|
|
80
|
+
textClassName = "uppercase",
|
|
81
|
+
children,
|
|
82
|
+
className,
|
|
83
|
+
...rest
|
|
84
|
+
}: BadgeProps) => {
|
|
85
|
+
const fontColor = useMemo(
|
|
86
|
+
() => BadgeFontColor[color] ?? "text-white",
|
|
87
|
+
[color],
|
|
88
|
+
);
|
|
89
|
+
const BadgeClasses = useMemo(
|
|
90
|
+
() =>
|
|
91
|
+
twMerge(
|
|
92
|
+
fontColor,
|
|
93
|
+
category === "outline" ? BadgeOutline[color] : BadgeSolid[color],
|
|
94
|
+
BadgeRoundness[roundness],
|
|
95
|
+
BadgeSize[size],
|
|
96
|
+
),
|
|
97
|
+
[fontColor, category, color, size, roundness],
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<div
|
|
102
|
+
className={twMerge(
|
|
103
|
+
"ui-badge flex items-center font-bold",
|
|
104
|
+
BadgeClasses,
|
|
105
|
+
className,
|
|
106
|
+
)}
|
|
107
|
+
style={rest?.style}
|
|
108
|
+
data-testid={`badge`}
|
|
109
|
+
data-category={category}
|
|
110
|
+
data-color={color}
|
|
111
|
+
{...rest}
|
|
112
|
+
>
|
|
113
|
+
<p className={twMerge("mx-1", textClassName)}>{children}</p>
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Modal } from "../ui/modal";
|
|
3
|
+
import { InputField } from "../ui/input";
|
|
4
|
+
|
|
5
|
+
export const InitiatePlaybookModal = ({
|
|
6
|
+
onConfirm,
|
|
7
|
+
onClose,
|
|
8
|
+
isOpen,
|
|
9
|
+
title,
|
|
10
|
+
}: {
|
|
11
|
+
onConfirm: (email: string) => void | Promise<void>;
|
|
12
|
+
onClose: () => void;
|
|
13
|
+
isOpen: boolean;
|
|
14
|
+
title?: string;
|
|
15
|
+
}) => {
|
|
16
|
+
const [email, setEmail] = useState("");
|
|
17
|
+
const [isConfirming, setIsConfirming] = useState(false);
|
|
18
|
+
const handleConfirm = async () => {
|
|
19
|
+
if (email) {
|
|
20
|
+
try {
|
|
21
|
+
setIsConfirming(true);
|
|
22
|
+
await onConfirm(email);
|
|
23
|
+
setEmail(""); // Reset email after confirmation
|
|
24
|
+
} finally {
|
|
25
|
+
setIsConfirming(false);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
alert("Please enter a valid email address.");
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
return (
|
|
32
|
+
<Modal
|
|
33
|
+
title={title || "Initiate Confidence Playbook"}
|
|
34
|
+
isOpen={isOpen}
|
|
35
|
+
close={onClose}
|
|
36
|
+
dismissOptions={{ label: "Cancel", onClick: onClose }}
|
|
37
|
+
confirmOptions={{
|
|
38
|
+
label: "Initiate",
|
|
39
|
+
onClick: handleConfirm,
|
|
40
|
+
disabled: isConfirming || !email,
|
|
41
|
+
}}
|
|
42
|
+
>
|
|
43
|
+
<>
|
|
44
|
+
<InputField
|
|
45
|
+
label="Email"
|
|
46
|
+
disabled={isConfirming}
|
|
47
|
+
description="Enter the email address to initiate the playbook."
|
|
48
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
49
|
+
/>
|
|
50
|
+
</>
|
|
51
|
+
</Modal>
|
|
52
|
+
);
|
|
53
|
+
};
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
2
|
+
import { ReactNode, useEffect, useMemo, useState } from "react";
|
|
3
|
+
import { usePlaybook } from "../../hooks/usePlaybook";
|
|
4
|
+
import { TASK_BUTTONS, TaskButton } from "../../hooks/useTaskButtons";
|
|
5
|
+
import { Playbook } from "../../types/playbook.types";
|
|
6
|
+
import { TASK_STATUS } from "../../types/task.types";
|
|
7
|
+
import { cn } from "../../utils/cn";
|
|
8
|
+
import { ConfidenceTask } from "../task/confidence-task";
|
|
9
|
+
import { PlaybookHeader } from "./playbook-header";
|
|
10
|
+
import { initiatePlaybook } from "../../services/initiate-playbook.service";
|
|
11
|
+
|
|
12
|
+
const ConfidencePlaybookInternal = ({
|
|
13
|
+
playbookInstanceId,
|
|
14
|
+
viewMode,
|
|
15
|
+
}: {
|
|
16
|
+
playbookInstanceId: string | number;
|
|
17
|
+
viewMode: "list" | "card";
|
|
18
|
+
}) => {
|
|
19
|
+
const { playbook, actions: playbookActions } =
|
|
20
|
+
usePlaybook(playbookInstanceId);
|
|
21
|
+
if (!playbook) {
|
|
22
|
+
return <div>Playbook not found</div>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const handleButtonClick = (buttonType: TaskButton, taskId: number) => {
|
|
26
|
+
if (buttonType === TASK_BUTTONS.COMPLETE) {
|
|
27
|
+
const sequenceOrder = playbook.tasks.find(
|
|
28
|
+
(task) => task.taskInstanceId === taskId,
|
|
29
|
+
)?.sequenceOrder;
|
|
30
|
+
if (sequenceOrder === undefined) {
|
|
31
|
+
console.error("Task not found in playbook");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
playbookActions.completeTask(taskId, sequenceOrder);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (buttonType === TASK_BUTTONS.START) {
|
|
39
|
+
playbookActions.startTask(taskId);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div className="flex flex-col">
|
|
45
|
+
<PlaybookView
|
|
46
|
+
playbook={playbook}
|
|
47
|
+
viewMode={viewMode}
|
|
48
|
+
onTaskButtonClick={handleButtonClick}
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const TasksContainer = ({
|
|
55
|
+
className,
|
|
56
|
+
children,
|
|
57
|
+
}: {
|
|
58
|
+
className?: string;
|
|
59
|
+
children: React.ReactNode;
|
|
60
|
+
}) => {
|
|
61
|
+
return (
|
|
62
|
+
<div className={cn("w-full mx-auto space-y-4 py-4 container", className)}>
|
|
63
|
+
{children}
|
|
64
|
+
</div>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const Context = ({ children }: { children: ReactNode }) => {
|
|
69
|
+
const [queryClient] = useState(new QueryClient());
|
|
70
|
+
console.log("Confidence Playbook Context Initialized");
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const PlaybookView = ({
|
|
78
|
+
playbook,
|
|
79
|
+
viewMode,
|
|
80
|
+
onTaskButtonClick,
|
|
81
|
+
}: {
|
|
82
|
+
viewMode: "list" | "card";
|
|
83
|
+
playbook: Playbook;
|
|
84
|
+
onTaskButtonClick: (btn: TaskButton, taskId: number) => void;
|
|
85
|
+
}) => {
|
|
86
|
+
const { playbookInstanceName, tasks } = playbook;
|
|
87
|
+
|
|
88
|
+
const sequenceOrderToStart = useMemo(() => {
|
|
89
|
+
const lastCompletedTask = tasks.find(
|
|
90
|
+
(task) => task.workflowStatus === TASK_STATUS.COMPLETED,
|
|
91
|
+
);
|
|
92
|
+
if (!lastCompletedTask) {
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return lastCompletedTask.sequenceOrder + 1;
|
|
97
|
+
}, [tasks]);
|
|
98
|
+
return (
|
|
99
|
+
<div className="min-h-screen flex flex-col items-stretch bg-gray-50">
|
|
100
|
+
<PlaybookHeader title={playbookInstanceName} className="top-0 sticky" />
|
|
101
|
+
|
|
102
|
+
<TasksContainer
|
|
103
|
+
className={cn("flex-1", viewMode === "list" && "space-y-0")}
|
|
104
|
+
>
|
|
105
|
+
{tasks.map((task, index) => {
|
|
106
|
+
return (
|
|
107
|
+
<ConfidenceTask
|
|
108
|
+
key={index}
|
|
109
|
+
task={task}
|
|
110
|
+
step={index + 1}
|
|
111
|
+
viewMode={viewMode}
|
|
112
|
+
canStart={task.sequenceOrder === sequenceOrderToStart}
|
|
113
|
+
onButtonClick={(btn) => {
|
|
114
|
+
console.log("Button clicked:", btn);
|
|
115
|
+
onTaskButtonClick(btn, task.taskInstanceId);
|
|
116
|
+
}}
|
|
117
|
+
playbookType={"Non-Sequential"}
|
|
118
|
+
/>
|
|
119
|
+
);
|
|
120
|
+
})}
|
|
121
|
+
</TasksContainer>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const ConfidencePlaybook = ({
|
|
127
|
+
playbookInstanceId,
|
|
128
|
+
viewMode,
|
|
129
|
+
}: {
|
|
130
|
+
playbookInstanceId: string | number;
|
|
131
|
+
viewMode: "list" | "card";
|
|
132
|
+
}) => {
|
|
133
|
+
return (
|
|
134
|
+
<Context>
|
|
135
|
+
<ConfidencePlaybookInternal
|
|
136
|
+
playbookInstanceId={playbookInstanceId}
|
|
137
|
+
viewMode={viewMode}
|
|
138
|
+
/>
|
|
139
|
+
</Context>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const AutoInstantiated = ({
|
|
144
|
+
email,
|
|
145
|
+
playbookId,
|
|
146
|
+
viewMode,
|
|
147
|
+
}: {
|
|
148
|
+
email: string;
|
|
149
|
+
playbookId: string;
|
|
150
|
+
viewMode: "list" | "card";
|
|
151
|
+
}) => {
|
|
152
|
+
const [playbookInstanceId, setPlaybookInstanceId] = useState<number | null>(
|
|
153
|
+
null,
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
(async () => {
|
|
158
|
+
const { playbookInstanceId, errorCode, details, message } =
|
|
159
|
+
(await initiatePlaybook({
|
|
160
|
+
bank: "public-sdk",
|
|
161
|
+
email,
|
|
162
|
+
timezone:
|
|
163
|
+
Intl.DateTimeFormat().resolvedOptions().timeZone ||
|
|
164
|
+
"America/Los_Angeles",
|
|
165
|
+
playbookUid: playbookId,
|
|
166
|
+
})) || {};
|
|
167
|
+
|
|
168
|
+
if (errorCode) {
|
|
169
|
+
throw new Error(
|
|
170
|
+
`Error initiating playbook: ${message} (Code: ${errorCode}) - Details: ${details}`,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
setPlaybookInstanceId(playbookInstanceId);
|
|
175
|
+
})();
|
|
176
|
+
}, []);
|
|
177
|
+
|
|
178
|
+
if (!playbookInstanceId) {
|
|
179
|
+
return <div>Loading...</div>;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<ConfidencePlaybook
|
|
184
|
+
playbookInstanceId={playbookInstanceId}
|
|
185
|
+
viewMode={viewMode}
|
|
186
|
+
/>
|
|
187
|
+
);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
ConfidencePlaybook.Context = Context;
|
|
191
|
+
ConfidencePlaybook.View = PlaybookView;
|
|
192
|
+
ConfidencePlaybook.TasksContainer = TasksContainer;
|
|
193
|
+
ConfidencePlaybook.AutoInstantiated = AutoInstantiated;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const PlaybookHeader = ({
|
|
2
|
+
title,
|
|
3
|
+
className,
|
|
4
|
+
...props
|
|
5
|
+
}: React.ComponentProps<"div"> & { title: string }) => {
|
|
6
|
+
return (
|
|
7
|
+
<div className={className} {...props}>
|
|
8
|
+
<div className="border-y border-gray-200 bg-white">
|
|
9
|
+
<h1 className="container mx-auto py-3 text-2xl">{title}</h1>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
);
|
|
13
|
+
};
|