@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.
Files changed (68) hide show
  1. package/README.md +54 -0
  2. package/dist/components/badge.d.ts +54 -0
  3. package/dist/components/initiate-playbook-modal/InitiatePlaybookModal.d.ts +6 -0
  4. package/dist/components/playbook/confidence-playbook.d.ts +26 -0
  5. package/dist/components/playbook/playbook-header.d.ts +3 -0
  6. package/dist/components/playbook-button/ConfidencePlaybookButton.d.ts +8 -0
  7. package/dist/components/task/confidence-task.d.ts +17 -0
  8. package/dist/components/task/task-buttons.d.ts +5 -0
  9. package/dist/components/task/task-dropdown-badge.d.ts +18 -0
  10. package/dist/components/task/task-left-panel.d.ts +10 -0
  11. package/dist/components/task/task-status-badge.d.ts +9 -0
  12. package/dist/components/ui/button.d.ts +38 -0
  13. package/dist/components/ui/header.d.ts +1 -0
  14. package/dist/components/ui/input.d.ts +9 -0
  15. package/dist/components/ui/modal.d.ts +16 -0
  16. package/dist/constants/settings.constants.d.ts +2 -0
  17. package/dist/hooks/task-events/useCompleteTask.d.ts +99 -0
  18. package/dist/hooks/task-events/useStartTask.d.ts +99 -0
  19. package/dist/hooks/usePlaybook.d.ts +10 -0
  20. package/dist/hooks/usePlaybookActions.d.ts +6 -0
  21. package/dist/hooks/useTaskButtons.d.ts +17 -0
  22. package/dist/index.css +1 -0
  23. package/dist/index.d.ts +4 -0
  24. package/dist/sdk.cjs +604 -0
  25. package/dist/sdk.js +12079 -0
  26. package/dist/services/complete-task.service.d.ts +4 -0
  27. package/dist/services/initiate-playbook.service.d.ts +11 -0
  28. package/dist/services/start-task.services.d.ts +4 -0
  29. package/dist/stories/initiate-playbook-modal.stories.d.ts +19 -0
  30. package/dist/stories/modal.stories.d.ts +28 -0
  31. package/dist/stories/playbook-container.stories.d.ts +55 -0
  32. package/dist/types/playbook.types.d.ts +20 -0
  33. package/dist/types/task.types.d.ts +18 -0
  34. package/dist/utils/cn.d.ts +2 -0
  35. package/dist/vite.svg +1 -0
  36. package/package.json +66 -0
  37. package/src/App.css +2 -0
  38. package/src/components/badge.tsx +116 -0
  39. package/src/components/initiate-playbook-modal/InitiatePlaybookModal.tsx +53 -0
  40. package/src/components/playbook/confidence-playbook.tsx +193 -0
  41. package/src/components/playbook/playbook-header.tsx +13 -0
  42. package/src/components/playbook-button/ConfidencePlaybookButton.tsx +73 -0
  43. package/src/components/task/confidence-task.tsx +198 -0
  44. package/src/components/task/task-buttons.tsx +32 -0
  45. package/src/components/task/task-dropdown-badge.tsx +121 -0
  46. package/src/components/task/task-left-panel.tsx +60 -0
  47. package/src/components/task/task-status-badge.tsx +23 -0
  48. package/src/components/ui/button.tsx +269 -0
  49. package/src/components/ui/header.tsx +12 -0
  50. package/src/components/ui/input.tsx +39 -0
  51. package/src/components/ui/modal.tsx +88 -0
  52. package/src/constants/settings.constants.ts +2 -0
  53. package/src/hooks/task-events/useCompleteTask.ts +26 -0
  54. package/src/hooks/task-events/useStartTask.ts +29 -0
  55. package/src/hooks/usePlaybook.ts +48 -0
  56. package/src/hooks/usePlaybookActions.ts +69 -0
  57. package/src/hooks/useTaskButtons.ts +46 -0
  58. package/src/index.ts +6 -0
  59. package/src/services/complete-task.service.ts +21 -0
  60. package/src/services/initiate-playbook.service.ts +24 -0
  61. package/src/services/start-task.services.ts +23 -0
  62. package/src/stories/initiate-playbook-modal.stories.tsx +31 -0
  63. package/src/stories/modal.stories.tsx +50 -0
  64. package/src/stories/playbook-container.stories.tsx +79 -0
  65. package/src/types/playbook.types.ts +22 -0
  66. package/src/types/task.types.ts +20 -0
  67. package/src/utils/cn.ts +6 -0
  68. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,73 @@
1
+ import { useState } from "react";
2
+ import { initiatePlaybook } from "../../services/initiate-playbook.service";
3
+ import { InitiatePlaybookModal } from "../initiate-playbook-modal/InitiatePlaybookModal";
4
+ import Button, { ButtonSizeType } from "../ui/button";
5
+
6
+ export const ConfidencePlaybookButton = ({
7
+ btnClassName,
8
+ buttonNode,
9
+ size,
10
+ playbookId,
11
+ onInitiated,
12
+ }: {
13
+ btnClassName?: string;
14
+ buttonNode?: React.ReactNode;
15
+ size?: ButtonSizeType;
16
+ playbookId: string;
17
+ onInitiated: (playbookInstanceId: number) => void;
18
+ }) => {
19
+ const [isOpen, setIsOpen] = useState(false);
20
+
21
+ function open() {
22
+ setIsOpen(true);
23
+ }
24
+
25
+ function close() {
26
+ setIsOpen(false);
27
+ }
28
+
29
+ const onInitiatePlaybook = async (email: string) => {
30
+ const { playbookInstanceId, errorCode, details, message } =
31
+ (await initiatePlaybook({
32
+ bank: "public-sdk",
33
+ email,
34
+ timezone:
35
+ Intl.DateTimeFormat().resolvedOptions().timeZone ||
36
+ "America/Los_Angeles",
37
+ playbookUid: playbookId,
38
+ })) || {};
39
+
40
+ if (errorCode) {
41
+ throw new Error(
42
+ `Error initiating playbook: ${message} (Code: ${errorCode}) - Details: ${details}`,
43
+ );
44
+ }
45
+
46
+ onInitiated(playbookInstanceId);
47
+ };
48
+ return (
49
+ <>
50
+ {buttonNode ? (
51
+ { buttonNode }
52
+ ) : (
53
+ <Button
54
+ onClick={open}
55
+ className={btnClassName}
56
+ color="primary"
57
+ size={size}
58
+ >
59
+ Run Playbook
60
+ </Button>
61
+ )}
62
+
63
+ <InitiatePlaybookModal
64
+ isOpen={isOpen}
65
+ onClose={close}
66
+ onConfirm={async (email) => {
67
+ await onInitiatePlaybook(email);
68
+ close();
69
+ }}
70
+ />
71
+ </>
72
+ );
73
+ };
@@ -0,0 +1,198 @@
1
+ import clsx from "clsx";
2
+ import { TaskButton, useTaskButtons } from "../../hooks/useTaskButtons";
3
+ import { PlaybookType } from "../../types/playbook.types";
4
+ import { Task, TASK_STATUS, TaskStatus } from "../../types/task.types";
5
+ import { TaskButtons } from "./task-buttons";
6
+ import { TaskLeftPanel } from "./task-left-panel";
7
+ import { TaskStatusBadge } from "./task-status-badge";
8
+ import { faCheckSquare } from "@fortawesome/free-solid-svg-icons";
9
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
10
+ import { useMemo } from "react";
11
+ import { cn } from "../../utils/cn";
12
+ import { TaskDropdownBadge } from "./task-dropdown-badge";
13
+
14
+ const TASK_CARD_COLOR: {
15
+ [key in TaskStatus]?: string;
16
+ } = {
17
+ [TASK_STATUS.OPEN]: "border-[#C1C5C8] bg-[#F0F1F2]",
18
+ [TASK_STATUS.IN_PROGRESS]: "bg-[#E6F2FF] border-[#94C8FF]",
19
+ [TASK_STATUS.IN_REVIEW]: "bg-[#EAF6EC] border-[#A5DAB1]",
20
+ [TASK_STATUS.COMPLETED]: "bg-[#EAF6EC] border-[#A5DAB1]",
21
+ };
22
+
23
+ const TASK_VERIFICATION_TYPE = {
24
+ PHOTO: "photo",
25
+ SCREENSHOT: "screenshot",
26
+ } as const;
27
+
28
+ export type TaskVerificationType =
29
+ (typeof TASK_VERIFICATION_TYPE)[keyof typeof TASK_VERIFICATION_TYPE];
30
+
31
+ export const ConfidenceTask = ({
32
+ task,
33
+ step,
34
+ playbookType,
35
+ onButtonClick,
36
+ viewMode = "card",
37
+ canStart = false,
38
+ }: {
39
+ task: Task;
40
+ playbookType: PlaybookType;
41
+ step: number;
42
+ onButtonClick: (buttonType: TaskButton) => void;
43
+ viewMode?: "card" | "list";
44
+ canStart?: boolean;
45
+ }) => {
46
+ const { buttons } = useTaskButtons({
47
+ taskStatus: task.workflowStatus,
48
+ canStart,
49
+ });
50
+ const verificationType = useMemo(() => {
51
+ if (task.imageRequired === 0) {
52
+ return null;
53
+ }
54
+ if (task.imageRequired === 1) {
55
+ return TASK_VERIFICATION_TYPE.SCREENSHOT;
56
+ }
57
+ if (task.imageRequired === 2) {
58
+ return TASK_VERIFICATION_TYPE.PHOTO;
59
+ }
60
+ return null;
61
+ }, [task.imageRequired]);
62
+
63
+ if (viewMode === "list") {
64
+ const BADGE_VARIANT = useMemo(() => {
65
+ if (task.workflowStatus === TASK_STATUS.COMPLETED) {
66
+ return "success";
67
+ }
68
+
69
+ if (task.workflowStatus === TASK_STATUS.IN_PROGRESS) {
70
+ return "primary";
71
+ }
72
+ return "default";
73
+ }, [task.workflowStatus]);
74
+
75
+ const BADGE_TRANSICTIONS = useMemo(() => {
76
+ const transitions: {
77
+ color: "primary" | "success";
78
+ id: TaskButton;
79
+ action: string;
80
+ to: TaskStatus;
81
+ }[] = [];
82
+ buttons.forEach((button) => {
83
+ if (button === "START") {
84
+ transitions.push({
85
+ id: "START",
86
+ color: "primary",
87
+ action: "Start",
88
+ to: TASK_STATUS.IN_PROGRESS,
89
+ });
90
+ }
91
+
92
+ if (button === "COMPLETE") {
93
+ transitions.push({
94
+ id: "COMPLETE",
95
+ color: "success",
96
+ action: "Complete",
97
+ to: TASK_STATUS.COMPLETED,
98
+ });
99
+ }
100
+ });
101
+
102
+ return transitions;
103
+ }, [buttons]);
104
+ return (
105
+ <div className="flex gap-3 p-2 border-b border-gray-200">
106
+ <div className="text-gray-200 text-base">{task.sequenceOrder + 1}</div>
107
+ <div
108
+ className={cn(
109
+ "text-dark flex-1 truncate",
110
+ task.workflowStatus === TASK_STATUS.COMPLETED &&
111
+ "text-secondary-400 line-through",
112
+ )}
113
+ >
114
+ {task.taskInstanceName}
115
+ </div>
116
+ <TaskDropdownBadge
117
+ title={task.workflowStatus}
118
+ variant={BADGE_VARIANT}
119
+ transitions={BADGE_TRANSICTIONS}
120
+ onClick={(action) => {
121
+ onButtonClick(action as TaskButton);
122
+ }}
123
+ />
124
+ </div>
125
+ );
126
+ }
127
+
128
+ return (
129
+ <div
130
+ className={clsx(
131
+ "flex items-stretch rounded-sm overflow-hidden border",
132
+ TASK_CARD_COLOR[task.workflowStatus],
133
+ )}
134
+ >
135
+ <TaskLeftPanel
136
+ playbookType={playbookType}
137
+ status={task.workflowStatus}
138
+ step={step}
139
+ />
140
+ {/* <input
141
+ type="file"
142
+ ref={photoInputRef}
143
+ hidden
144
+ onChange={(e) => {
145
+ if (e.target.files?.length) {
146
+ void onUploadAsset(e.target.files[0]);
147
+ handleExpand(true);
148
+ }
149
+ }}
150
+ /> */}
151
+ <div className="flex w-full flex-col overflow-x-hidden p-2">
152
+ {playbookType === "Sequential" && (
153
+ <div className="-mb-3 elf-end pr-2 pt-2">
154
+ <TaskStatusBadge status={task.workflowStatus} />
155
+ </div>
156
+ )}
157
+
158
+ <div className="space-y-2 divide-y divide-black/20 flex flex-1 flex-col">
159
+ <div className="space-y-2">
160
+ <div className="text-lg font-medium text-[#1C232D] flex-1">
161
+ {task.taskInstanceName}
162
+ </div>
163
+
164
+ {verificationType ? (
165
+ <div className="flex items-center gap-2 text-sm">
166
+ <FontAwesomeIcon icon={faCheckSquare} className="size-[16px]" />
167
+ <div>
168
+ <span className="font-medium">
169
+ {verificationType === TASK_VERIFICATION_TYPE.PHOTO
170
+ ? "Photo"
171
+ : "Screenshot"}
172
+ </span>{" "}
173
+ required
174
+ </div>
175
+ </div>
176
+ ) : (
177
+ <></>
178
+ )}
179
+ </div>
180
+ {/* <div>
181
+ <PublicTaskExpandedContent
182
+ showScreenshotHints={showScreenshotHints}
183
+ description={taskDetails?.description}
184
+ onUploadScreenshot={handleUploadScreenshot}
185
+ onDeleteAsset={onDeleteAsset}
186
+ closeScreenshotHints={() => setShowScreenshotHints(false)}
187
+ taskAssets={taskAssets}
188
+ />
189
+ </div> */}
190
+
191
+ {buttons.length > 0 && (
192
+ <TaskButtons buttons={buttons} onButtonClick={onButtonClick} />
193
+ )}
194
+ </div>
195
+ </div>
196
+ </div>
197
+ );
198
+ };
@@ -0,0 +1,32 @@
1
+ import {
2
+ TASK_BUTTONS_DISPLAY_TEXT,
3
+ TaskButton,
4
+ } from "../../hooks/useTaskButtons";
5
+ import Button from "../ui/button";
6
+
7
+ export const TaskButtons = ({
8
+ buttons,
9
+ onButtonClick,
10
+ }: {
11
+ buttons: TaskButton[];
12
+ onButtonClick: (buttonType: TaskButton) => void;
13
+ }) => {
14
+ return (
15
+ <div className="flex items-center justify-end">
16
+ {buttons.map((button) => {
17
+ return (
18
+ <Button
19
+ key={button}
20
+ size="smallCollapse"
21
+ className="ml-2"
22
+ onClick={() => {
23
+ onButtonClick(button);
24
+ }}
25
+ >
26
+ {TASK_BUTTONS_DISPLAY_TEXT[button]}
27
+ </Button>
28
+ );
29
+ })}
30
+ </div>
31
+ );
32
+ };
@@ -0,0 +1,121 @@
1
+ import { useDismiss, useFloating, useInteractions } from "@floating-ui/react";
2
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3
+ import { cn } from "../../utils/cn";
4
+ import { faArrowRight, faChevronDown } from "@fortawesome/free-solid-svg-icons";
5
+ import { Badge } from "../badge";
6
+ import { useState } from "react";
7
+ const TASK_DROPDOWN_BADGE_VARIANTS = {
8
+ default: "text-secondary-600 border-secondary-600",
9
+ primary: "text-primary-600 border-primary-600",
10
+ success: "text-success-600 border-success-600",
11
+ } as const;
12
+
13
+ interface TaskDropdownBadgeProps {
14
+ title: string;
15
+ variant?: keyof typeof TASK_DROPDOWN_BADGE_VARIANTS;
16
+ transitions: {
17
+ id: string;
18
+ color: "primary" | "success";
19
+ action: string;
20
+ to: string;
21
+ }[];
22
+ onClick?: (action: string) => void;
23
+ }
24
+
25
+ const MenuItem = ({
26
+ transition,
27
+ onClick,
28
+ }: {
29
+ transition: {
30
+ id: string;
31
+ color: "primary" | "success";
32
+ action: string;
33
+ to: string;
34
+ };
35
+ onClick: () => void;
36
+ }) => {
37
+ return (
38
+ <div
39
+ className="py-1 px-3 space-x-2 flex items-center hover:bg-gray-100 cursor-pointer"
40
+ onClick={(e) => {
41
+ e.stopPropagation();
42
+ onClick();
43
+ }}
44
+ >
45
+ <span className="text-base text-dark flex-1">{transition.action}</span>
46
+ <FontAwesomeIcon icon={faArrowRight} className="text-gray-400" />
47
+ <Badge category="outline" color={transition.color}>
48
+ {transition.to}
49
+ </Badge>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export const TaskDropdownBadge = ({
55
+ title,
56
+ variant = "default",
57
+ transitions,
58
+ onClick,
59
+ }: TaskDropdownBadgeProps) => {
60
+ const [isOpen, setIsOpen] = useState(false);
61
+
62
+ const { refs, floatingStyles, context } = useFloating({
63
+ strategy: "fixed",
64
+ placement: "bottom-end",
65
+ open: isOpen,
66
+ onOpenChange: setIsOpen,
67
+ });
68
+
69
+ const dismiss = useDismiss(context, {
70
+ outsidePress: true,
71
+ });
72
+ const { getReferenceProps, getFloatingProps } = useInteractions([dismiss]);
73
+ return (
74
+ <>
75
+ <div
76
+ onClick={
77
+ transitions?.length ? () => setIsOpen((prev) => !prev) : undefined
78
+ }
79
+ ref={refs.setReference}
80
+ className={cn(
81
+ "px-1 uppercase border rounded-sm",
82
+ transitions.length ? "cursor-pointer" : "pointer-events-none",
83
+ TASK_DROPDOWN_BADGE_VARIANTS[variant],
84
+ )}
85
+ {...getReferenceProps()}
86
+ >
87
+ <span className="text-sm font-bold">{title}</span>
88
+ {transitions.length > 0 ? (
89
+ <FontAwesomeIcon
90
+ icon={faChevronDown}
91
+ className="text-gray-400 ml-1"
92
+ />
93
+ ) : (
94
+ <></>
95
+ )}
96
+ </div>
97
+
98
+ {isOpen && transitions.length && (
99
+ <div
100
+ ref={refs.setFloating}
101
+ style={floatingStyles}
102
+ className={cn(
103
+ "border border-gray-200 py-1.5 rounded-sm min-w-[172px] bg-white shadow-dark/50",
104
+ )}
105
+ {...getFloatingProps()}
106
+ >
107
+ {transitions.map((transition, index) => (
108
+ <MenuItem
109
+ key={index}
110
+ transition={transition}
111
+ onClick={() => {
112
+ onClick?.(transition.id as string);
113
+ setIsOpen(false);
114
+ }}
115
+ />
116
+ ))}
117
+ </div>
118
+ )}
119
+ </>
120
+ );
121
+ };
@@ -0,0 +1,60 @@
1
+ import clsx from "clsx";
2
+ import { TaskStatus, TASK_STATUS } from "../../types/task.types";
3
+ import { PLAYBOOK_TYPES, PlaybookType } from "../../types/playbook.types";
4
+
5
+ export interface TaskCardV2LeftPanelProps {
6
+ playbookType: PlaybookType;
7
+ status: TaskStatus;
8
+ step: number;
9
+ isSelected?: boolean;
10
+ onSelect?: (withShiftKey?: boolean) => void;
11
+ }
12
+
13
+ const LEFT_PANEL_FORMATTED_LABELS: {
14
+ [key in TaskStatus]?: string;
15
+ } = {
16
+ [TASK_STATUS.IN_REVIEW]: "In Review",
17
+ };
18
+
19
+ const LEFT_PANEL_COLOR: {
20
+ [key in TaskStatus]?: string;
21
+ } = {
22
+ [TASK_STATUS.OPEN]: "bg-secondary-500",
23
+ [TASK_STATUS.IN_PROGRESS]: "bg-primary-600",
24
+ [TASK_STATUS.IN_REVIEW]: "bg-success-600",
25
+ [TASK_STATUS.COMPLETED]: "bg-success-600",
26
+ };
27
+
28
+ export const TaskLeftPanel = ({
29
+ playbookType,
30
+ status,
31
+ step,
32
+ isSelected,
33
+ onSelect,
34
+ }: TaskCardV2LeftPanelProps) => {
35
+ return (
36
+ <div
37
+ className={clsx(
38
+ "flex flex-col items-center justify-center",
39
+ isSelected ? "bg-[#FFE600]" : LEFT_PANEL_COLOR[status],
40
+ onSelect && "cursor-pointer",
41
+ )}
42
+ onClick={(e) => {
43
+ e.stopPropagation();
44
+ onSelect?.(e.shiftKey);
45
+ }}
46
+ >
47
+ <span
48
+ className={clsx(
49
+ `text-orientation-mixed w-[27px] flex items-center whitespace-nowrap px-2 text-sm font-bold [writing-mode:vertical-lr]`,
50
+ isSelected ? "text-black" : "text-white",
51
+ )}
52
+ >
53
+ {/** TODO: check "status" wording */}
54
+ {playbookType === PLAYBOOK_TYPES.SEQUENTIAL
55
+ ? `STEP ${step}`
56
+ : (LEFT_PANEL_FORMATTED_LABELS[status] || status).toUpperCase()}
57
+ </span>
58
+ </div>
59
+ );
60
+ };
@@ -0,0 +1,23 @@
1
+ import { TASK_STATUS, TaskStatus } from "../../types/task.types";
2
+ import { Badge, BadgeSolid } from "../badge";
3
+
4
+ export interface TaskCardV2StatusBadgeProps {
5
+ status: TaskStatus;
6
+ }
7
+
8
+ export const STATUS_BADGE_COLOR: {
9
+ [key in TaskStatus]?: keyof typeof BadgeSolid;
10
+ } = {
11
+ [TASK_STATUS.OPEN]: "secondary",
12
+ [TASK_STATUS.IN_PROGRESS]: "primary",
13
+ [TASK_STATUS.IN_REVIEW]: "success",
14
+ [TASK_STATUS.COMPLETED]: "success",
15
+ } as const;
16
+
17
+ export const TaskStatusBadge = ({ status }: TaskCardV2StatusBadgeProps) => {
18
+ return (
19
+ <Badge category="outline" color={STATUS_BADGE_COLOR[status]}>
20
+ {status}
21
+ </Badge>
22
+ );
23
+ };