@powerhousedao/contributor-billing 0.0.92 → 0.0.93

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.
@@ -1 +1 @@
1
- {"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DriveExplorer.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,gBAAgB,EAUtB,MAAM,gCAAgC,CAAC;AAUxC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,gBAAgB,2CAuWpD"}
1
+ {"version":3,"file":"DriveExplorer.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/components/DriveExplorer.tsx"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,gBAAgB,EAStB,MAAM,gCAAgC,CAAC;AAQxC;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,gBAAgB,2CAkXpD"}
@@ -1,11 +1,9 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { CreateDocumentModal, useDrop } from "@powerhousedao/design-system";
3
- import { addDocument, useDocumentModelModules, useDriveContext, useDriveSharingType, useEditorModules, useFileChildNodes, useSelectedDrive, useSelectedDriveDocuments, useSelectedFolder, useSelectedNodePath, } from "@powerhousedao/reactor-browser";
2
+ import { CreateDocumentModal, ToastContainer, } from "@powerhousedao/design-system";
3
+ import { addDocument, useDocumentModelModules, useEditorModules, useFileChildNodes, useSelectedDrive, useSelectedDriveDocuments, useSelectedFolder, useNodeActions, showDeleteNodeModal, } from "@powerhousedao/reactor-browser";
4
4
  import { useCallback, useEffect, useRef, useState } from "react";
5
5
  import { EditorContainer } from "./EditorContainer.js";
6
6
  import { InvoiceTable } from "./InvoiceTable/InvoiceTable.js";
7
- import { twMerge } from "tailwind-merge";
8
- import { ToastContainer } from "@powerhousedao/design-system";
9
7
  import { HeaderStats } from "./InvoiceTable/HeaderStats.js";
10
8
  /**
11
9
  * Main drive explorer component with sidebar navigation and content area.
@@ -24,24 +22,13 @@ export function DriveExplorer(props) {
24
22
  const [openModal, setOpenModal] = useState(false);
25
23
  const selectedDocumentModel = useRef(null);
26
24
  const editorModules = useEditorModules();
27
- // === DRIVE CONTEXT HOOKS ===
28
- // Core drive operations and document models
29
- const { onAddFile, onAddFolder, onCopyNode, onMoveNode } = useDriveContext();
25
+ // === NODE ACTIONS HOOK ===
26
+ // Get all node operations from reactor-browser
27
+ const { onRenameNode, onDuplicateNode } = useNodeActions();
30
28
  // === STATE MANAGEMENT HOOKS ===
31
29
  // Core state hooks for drive navigation
32
30
  const [selectedDrive] = useSelectedDrive(); // Currently selected drive
33
31
  const selectedFolder = useSelectedFolder(); // Currently selected folder
34
- const selectedNodePath = useSelectedNodePath();
35
- const sharingType = useDriveSharingType(selectedDrive?.header.id);
36
- // === DROP HOOKS ===
37
- const { isDropTarget, dropProps } = useDrop({
38
- node: selectedNodePath?.length > 0
39
- ? selectedNodePath[selectedNodePath.length - 1]
40
- : undefined,
41
- onAddFile,
42
- onCopyNode,
43
- onMoveNode,
44
- });
45
32
  const fileChildren = useFileChildNodes();
46
33
  // All document states
47
34
  const allDocuments = useSelectedDriveDocuments();
@@ -64,12 +51,12 @@ export function DriveExplorer(props) {
64
51
  "PAYMENTCLOSED",
65
52
  ];
66
53
  // Get all selected row IDs
67
- const selectedRowIds = Object.keys(selected).filter(id => selected[id]);
54
+ const selectedRowIds = Object.keys(selected).filter((id) => selected[id]);
68
55
  if (selectedRowIds.length === 0)
69
56
  return false;
70
57
  // Check if all selected rows have allowed statuses
71
- const selectedRows = state?.filter(doc => selectedRowIds.includes(doc.header.id)) || [];
72
- return selectedRows.every(row => allowedStatuses.includes(row.state.global.status));
58
+ const selectedRows = state?.filter((doc) => selectedRowIds.includes(doc.header.id)) || [];
59
+ return selectedRows.every((row) => allowedStatuses.includes(row.state.global.status));
73
60
  }, [selected, state]);
74
61
  // Create a stable dispatcher map using useRef only (no useState to avoid re-renders)
75
62
  const dispatchersRef = useRef(new Map());
@@ -166,23 +153,38 @@ export function DriveExplorer(props) {
166
153
  return dispatchersRef.current.get(id) || null;
167
154
  };
168
155
  // === EVENT HANDLERS ===
169
- // Handle folder creation with optional name parameter
170
- const handleCreateFolder = useCallback(async (folderName) => {
171
- let name = folderName;
172
- // If no name provided, prompt for it (for manual folder creation)
173
- if (!name) {
174
- const promptResult = prompt("Enter folder name:");
175
- name = promptResult || undefined;
156
+ // Wrapper for rename that handles node ID
157
+ const handleRenameNode = useCallback(async (nodeId, newName) => {
158
+ const node = fileChildren.find((n) => n.id === nodeId);
159
+ if (node) {
160
+ await onRenameNode(newName, node);
176
161
  }
177
- if (name?.trim()) {
178
- try {
179
- await onAddFolder(name.trim(), selectedFolder);
180
- }
181
- catch (error) {
182
- console.error("Failed to create folder:", error);
183
- }
162
+ }, [fileChildren, onRenameNode]);
163
+ // Wrapper for delete that clears selection
164
+ const handleDeleteNode = useCallback(async (nodeId) => {
165
+ const node = fileChildren.find((n) => n.id === nodeId);
166
+ if (node &&
167
+ window.confirm(`Are you sure you want to delete "${node.name}"?`)) {
168
+ // Delete via context menu or direct call
169
+ // The FileItem component will call showDeleteNodeModal instead
170
+ setSelected((prev) => {
171
+ const newSelected = { ...prev };
172
+ delete newSelected[nodeId];
173
+ return newSelected;
174
+ });
184
175
  }
185
- }, [onAddFolder, selectedFolder]);
176
+ }, [fileChildren]);
177
+ // Wrapper for showDeleteNodeModal (for FileItem) - uses the reactor-browser function
178
+ const handleShowDeleteModal = useCallback(async (node) => {
179
+ showDeleteNodeModal(node.id);
180
+ // Clear selection after deletion is confirmed
181
+ setSelected((prev) => {
182
+ const newSelected = { ...prev };
183
+ delete newSelected[node.id];
184
+ return newSelected;
185
+ });
186
+ return undefined;
187
+ }, []);
186
188
  // Handle document creation from modal
187
189
  const onCreateDocument = useCallback(async (fileName) => {
188
190
  setOpenModal(false);
@@ -222,11 +224,10 @@ export function DriveExplorer(props) {
222
224
  ? editorModules?.find((e) => e.documentTypes.includes(activeDocument.documentType))
223
225
  : null;
224
226
  // === RENDER ===
225
- // console.log("files", fileChildren);
226
- // console.log("state", state);
227
- // console.log("isDropTarget", isDropTarget);
228
- // console.log("dropProps", dropProps);
229
- return (_jsx("div", { className: "flex h-full editor-container", children: _jsxs("div", { ...dropProps, className: twMerge("rounded-md border-2 border-transparent ", isDropTarget && "border-dashed border-blue-100"), children: [_jsx(ToastContainer, { position: "bottom-right", autoClose: 5000, hideProgressBar: false, newestOnTop: false, closeOnClick: false, rtl: false, pauseOnFocusLoss: true, draggable: true, pauseOnHover: true, theme: "light" }), _jsx("div", { className: "flex-1 p-4", children: activeDocument && documentModelModule && editorModule ? (
227
+ return (_jsx("div", { className: "flex h-full editor-container", children: _jsxs("div", { className: "h-full", children: [_jsx(ToastContainer, { position: "bottom-right", autoClose: 5000, hideProgressBar: false, newestOnTop: false, closeOnClick: false, rtl: false, pauseOnFocusLoss: true, draggable: true, pauseOnHover: true, theme: "light" }), _jsx("div", { className: "flex-1 p-4", children: activeDocument && documentModelModule && editorModule ? (
230
228
  // Document editor view
231
- _jsx(EditorContainer, { handleClose: () => setActiveDocumentId(undefined), activeDocumentId: activeDocumentId || "" })) : (_jsxs(_Fragment, { children: [_jsx(HeaderStats, {}), _jsx(InvoiceTable, { setActiveDocumentId: setActiveDocumentId, files: fileChildren, state: state || [], selected: selected, setSelected: setSelected, onBatchAction: () => { }, onDeleteNode: () => { }, renameNode: () => { }, filteredDocumentModels: documentModelModules, onSelectDocumentModel: onSelectDocumentModel, getDocDispatcher: getDocDispatcher, selectedStatuses: selectedStatuses, onStatusChange: handleStatusChange, onRowSelection: handleRowSelection, canExportSelectedRows: canExportSelectedRows })] })) }), _jsx(CreateDocumentModal, { onContinue: onCreateDocument, onOpenChange: (open) => setOpenModal(open), open: openModal })] }) }));
229
+ _jsx(EditorContainer, { handleClose: () => setActiveDocumentId(undefined), activeDocumentId: activeDocumentId || "" })) : (_jsxs(_Fragment, { children: [_jsx(HeaderStats, {}), _jsx(InvoiceTable, { setActiveDocumentId: setActiveDocumentId, files: fileChildren, state: state || [], selected: selected, setSelected: setSelected, onBatchAction: () => { }, onDeleteNode: handleDeleteNode, renameNode: handleRenameNode, onDuplicateNode: async (node) => {
230
+ await onDuplicateNode(node);
231
+ return undefined;
232
+ }, showDeleteNodeModal: handleShowDeleteModal, filteredDocumentModels: documentModelModules, onSelectDocumentModel: onSelectDocumentModel, getDocDispatcher: getDocDispatcher, selectedStatuses: selectedStatuses, onStatusChange: handleStatusChange, onRowSelection: handleRowSelection, canExportSelectedRows: canExportSelectedRows })] })) }), _jsx(CreateDocumentModal, { onContinue: onCreateDocument, onOpenChange: (open) => setOpenModal(open), open: openModal })] }) }));
232
233
  }
@@ -1,3 +1,4 @@
1
+ import type { Node } from "document-drive";
1
2
  import { type DocumentModelModule } from "document-model";
2
3
  interface InvoiceTableProps {
3
4
  files: any[];
@@ -16,6 +17,8 @@ interface InvoiceTableProps {
16
17
  onBatchAction: (action: string) => void;
17
18
  onDeleteNode: (nodeId: string) => void;
18
19
  renameNode: (nodeId: string, name: string) => void;
20
+ onDuplicateNode: (node: Node) => Promise<Node | undefined>;
21
+ showDeleteNodeModal: (node: Node) => Promise<Node | undefined>;
19
22
  filteredDocumentModels: DocumentModelModule[];
20
23
  onSelectDocumentModel: (model: DocumentModelModule) => void;
21
24
  getDocDispatcher: (id: string) => any;
@@ -24,6 +27,6 @@ interface InvoiceTableProps {
24
27
  onRowSelection: (rowId: string, checked: boolean, rowStatus: string) => void;
25
28
  canExportSelectedRows: () => boolean;
26
29
  }
27
- export declare const InvoiceTable: ({ files, state, setActiveDocumentId, selected, setSelected, onBatchAction, onDeleteNode, renameNode, filteredDocumentModels, onSelectDocumentModel, getDocDispatcher, selectedStatuses, onStatusChange, onRowSelection, canExportSelectedRows, }: InvoiceTableProps) => import("react/jsx-runtime").JSX.Element;
30
+ export declare const InvoiceTable: ({ files, state, setActiveDocumentId, selected, setSelected, onBatchAction, onDeleteNode, renameNode, onDuplicateNode, showDeleteNodeModal, filteredDocumentModels, onSelectDocumentModel, getDocDispatcher, selectedStatuses, onStatusChange, onRowSelection, canExportSelectedRows, }: InvoiceTableProps) => import("react/jsx-runtime").JSX.Element;
28
31
  export {};
29
32
  //# sourceMappingURL=InvoiceTable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"InvoiceTable.d.ts","sourceRoot":"","sources":["../../../../../editors/contributor-billing/components/InvoiceTable/InvoiceTable.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AA2B1D,UAAU,iBAAiB;IACzB,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;IAC7B,mBAAmB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,EAAE;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACpC,WAAW,EAAE,CACX,QAAQ,EACJ;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GACzB,CAAC,CAAC,IAAI,EAAE;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,KAAK;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,KACjE,IAAI,CAAC;IACV,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,sBAAsB,EAAE,mBAAmB,EAAE,CAAC;IAC9C,qBAAqB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC5D,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,GAAG,CAAC;IACtC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7E,qBAAqB,EAAE,MAAM,OAAO,CAAC;CACtC;AAED,eAAO,MAAM,YAAY,GAAI,kPAgB1B,iBAAiB,4CAwoBnB,CAAC"}
1
+ {"version":3,"file":"InvoiceTable.d.ts","sourceRoot":"","sources":["../../../../../editors/contributor-billing/components/InvoiceTable/InvoiceTable.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AA2B1D,UAAU,iBAAiB;IACzB,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;IAC7B,mBAAmB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,EAAE;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACpC,WAAW,EAAE,CACX,QAAQ,EACJ;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GACzB,CAAC,CAAC,IAAI,EAAE;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,KAAK;QAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC,KACjE,IAAI,CAAC;IACV,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,eAAe,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAC3D,mBAAmB,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAC/D,sBAAsB,EAAE,mBAAmB,EAAE,CAAC;IAC9C,qBAAqB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAC5D,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,GAAG,CAAC;IACtC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7E,qBAAqB,EAAE,MAAM,OAAO,CAAC;CACtC;AAED,eAAO,MAAM,YAAY,GAAI,wRAkB1B,iBAAiB,4CA0pBnB,CAAC"}
@@ -20,7 +20,7 @@ const statusOptions = [
20
20
  { label: "Rejected", value: "REJECTED" },
21
21
  { label: "Other", value: "OTHER" },
22
22
  ];
23
- export const InvoiceTable = ({ files, state, setActiveDocumentId, selected, setSelected, onBatchAction, onDeleteNode, renameNode, filteredDocumentModels, onSelectDocumentModel, getDocDispatcher, selectedStatuses, onStatusChange, onRowSelection, canExportSelectedRows, }) => {
23
+ export const InvoiceTable = ({ files, state, setActiveDocumentId, selected, setSelected, onBatchAction, onDeleteNode, renameNode, onDuplicateNode, showDeleteNodeModal, filteredDocumentModels, onSelectDocumentModel, getDocDispatcher, selectedStatuses, onStatusChange, onRowSelection, canExportSelectedRows, }) => {
24
24
  const [selectedDrive] = useSelectedDrive();
25
25
  const billingDocStates = state
26
26
  .filter((doc) => doc.header.documentType === "powerhouse/billing-statement")
@@ -214,5 +214,5 @@ export const InvoiceTable = ({ files, state, setActiveDocumentId, selected, setS
214
214
  setActiveDocumentId(createdNode.id);
215
215
  }
216
216
  };
217
- return (_jsxs("div", { className: "w-full h-full bg-white rounded-lg p-4 border border-gray-200 shadow-md mt-4 overflow-x-auto", children: [_jsx(HeaderControls, { statusOptions: statusOptions, onStatusChange: onStatusChange, onBatchAction: onBatchAction, onExport: handleCSVExport, selectedStatuses: selectedStatuses, createIntegrationsDocument: createIntegrationsDocument, integrationsDoc: integrationsDoc, setActiveDocumentId: setActiveDocumentId, canExportSelectedRows: canExportSelectedRows }), shouldShowSection("DRAFT") && (_jsx(InvoiceTableSection, { title: "Draft", count: draft.length, onSelectDocumentModel: onSelectDocumentModel, filteredDocumentModels: filteredDocumentModels, children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: draft.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode }, row.id))) })] }) })), shouldShowSection("ISSUED") && (_jsx(InvoiceTableSection, { title: "Issued", count: issued.length, children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: issued.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("ACCEPTED") && (_jsx(InvoiceTableSection, { title: "Accepted", count: accepted.length, color: "bg-green-100 text-green-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: accepted.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("PAYMENTSCHEDULED") && (_jsx(InvoiceTableSection, { title: "Payment Scheduled", count: paymentScheduled.length, color: "bg-green-100 text-green-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: paymentScheduled.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("PAYMENTSENT") && (_jsx(InvoiceTableSection, { title: "Payment Sent", count: paymentSent.length, color: "bg-green-100 text-green-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: paymentSent.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("PAYMENTISSUE") && (_jsx(InvoiceTableSection, { title: "Payment Issue", count: paymentIssue.length, color: "bg-yellow-100 text-yellow-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: paymentIssue.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("PAYMENTCLOSED") && (_jsx(InvoiceTableSection, { title: "Payment Closed", count: paymentClosed.length, color: "bg-red-500 text-black-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: paymentClosed.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode }, row.id))) })] }) })), shouldShowSection("REJECTED") && (_jsx(InvoiceTableSection, { title: "Rejected", count: rejected.length, color: "bg-red-500 text-black-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: rejected.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode }, row.id))) })] }) })), shouldShowSection("OTHER") && (_jsx(InvoiceTableSection, { title: "Other", count: otherInvoices.length, children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Exported" })] }) }), _jsx("tbody", { children: otherInvoices.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode }, row.id))) })] }) }))] }, `${state.length}`));
217
+ return (_jsxs("div", { className: "w-full h-full bg-white rounded-lg p-4 border border-gray-200 shadow-md mt-4 overflow-x-auto", children: [_jsx(HeaderControls, { statusOptions: statusOptions, onStatusChange: onStatusChange, onBatchAction: onBatchAction, onExport: handleCSVExport, selectedStatuses: selectedStatuses, createIntegrationsDocument: createIntegrationsDocument, integrationsDoc: integrationsDoc, setActiveDocumentId: setActiveDocumentId, canExportSelectedRows: canExportSelectedRows }), shouldShowSection("DRAFT") && (_jsx(InvoiceTableSection, { title: "Draft", count: draft.length, onSelectDocumentModel: onSelectDocumentModel, filteredDocumentModels: filteredDocumentModels, children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: draft.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal }, row.id))) })] }) })), shouldShowSection("ISSUED") && (_jsx(InvoiceTableSection, { title: "Issued", count: issued.length, children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: issued.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("ACCEPTED") && (_jsx(InvoiceTableSection, { title: "Accepted", count: accepted.length, color: "bg-green-100 text-green-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: accepted.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("PAYMENTSCHEDULED") && (_jsx(InvoiceTableSection, { title: "Payment Scheduled", count: paymentScheduled.length, color: "bg-green-100 text-green-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: paymentScheduled.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("PAYMENTSENT") && (_jsx(InvoiceTableSection, { title: "Payment Sent", count: paymentSent.length, color: "bg-green-100 text-green-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: paymentSent.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("PAYMENTISSUE") && (_jsx(InvoiceTableSection, { title: "Payment Issue", count: paymentIssue.length, color: "bg-yellow-100 text-yellow-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Billing Statement" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: paymentIssue.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal, onCreateBillingStatement: handleCreateBillingStatement, billingDocStates: billingDocStates }, row.id))) })] }) })), shouldShowSection("PAYMENTCLOSED") && (_jsx(InvoiceTableSection, { title: "Payment Closed", count: paymentClosed.length, color: "bg-red-500 text-black-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: paymentClosed.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal }, row.id))) })] }) })), shouldShowSection("REJECTED") && (_jsx(InvoiceTableSection, { title: "Rejected", count: rejected.length, color: "bg-red-500 text-black-600", children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2", children: "Exported" })] }) }), _jsx("tbody", { children: rejected.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal }, row.id))) })] }) })), shouldShowSection("OTHER") && (_jsx(InvoiceTableSection, { title: "Other", count: otherInvoices.length, children: _jsxs("table", { className: "w-full text-sm border-separate border-spacing-0 border border-gray-400", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-gray-50", children: [_jsx("th", { className: "px-2 py-2 w-8" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issuer" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Invoice No." }), _jsx("th", { className: "px-2 py-2 text-center", children: "Issue Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Due Date" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Currency" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Amount" }), _jsx("th", { className: "px-2 py-2 text-center", children: "Exported" })] }) }), _jsx("tbody", { children: otherInvoices.map((row) => (_jsx(InvoiceTableRow, { files: files, row: row, isSelected: !!selected[row.id], onSelect: (checked) => onRowSelection(row.id, checked, row.status), setActiveDocumentId: setActiveDocumentId, onDeleteNode: handleDelete, renameNode: renameNode, onDuplicateNode: onDuplicateNode, showDeleteNodeModal: showDeleteNodeModal }, row.id))) })] }) }))] }, `${state.length}`));
218
218
  };
@@ -1,4 +1,5 @@
1
- export declare const InvoiceTableRow: ({ files, row, isSelected, onSelect, setActiveDocumentId, onDeleteNode, renameNode, onCreateBillingStatement, billingDocStates, }: {
1
+ import type { Node } from "document-drive";
2
+ export declare const InvoiceTableRow: ({ files, row, isSelected, onSelect, setActiveDocumentId, onDeleteNode, renameNode, onDuplicateNode, showDeleteNodeModal, onCreateBillingStatement, billingDocStates, }: {
2
3
  files?: any[];
3
4
  row: any;
4
5
  isSelected: boolean;
@@ -6,6 +7,8 @@ export declare const InvoiceTableRow: ({ files, row, isSelected, onSelect, setAc
6
7
  setActiveDocumentId: (id: string) => void;
7
8
  onDeleteNode: (nodeId: string) => void;
8
9
  renameNode: (nodeId: string, name: string) => void;
10
+ onDuplicateNode?: (node: Node) => Promise<Node | undefined>;
11
+ showDeleteNodeModal?: (node: Node) => Promise<Node | undefined>;
9
12
  onCreateBillingStatement?: (id: string) => void;
10
13
  billingDocStates?: {
11
14
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"InvoiceTableRow.d.ts","sourceRoot":"","sources":["../../../../../editors/contributor-billing/components/InvoiceTable/InvoiceTableRow.tsx"],"names":[],"mappings":"AAKA,eAAO,MAAM,eAAe,GAAI,kIAU7B;IACD,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IACd,GAAG,EAAE,GAAG,CAAC;IACT,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,mBAAmB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,wBAAwB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,gBAAgB,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1D,4CAgLA,CAAC"}
1
+ {"version":3,"file":"InvoiceTableRow.d.ts","sourceRoot":"","sources":["../../../../../editors/contributor-billing/components/InvoiceTable/InvoiceTableRow.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAE3C,eAAO,MAAM,eAAe,GAAI,wKAY7B;IACD,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IACd,GAAG,EAAE,GAAG,CAAC;IACT,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACrC,mBAAmB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAChE,wBAAwB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,gBAAgB,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC1D,4CAoLA,CAAC"}
@@ -1,8 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useRef } from "react";
3
3
  import { FileItem } from "@powerhousedao/design-system";
4
- import { useDriveContext } from "@powerhousedao/reactor-browser";
5
- export const InvoiceTableRow = ({ files, row, isSelected, onSelect, setActiveDocumentId, onDeleteNode, renameNode, onCreateBillingStatement, billingDocStates, }) => {
4
+ export const InvoiceTableRow = ({ files, row, isSelected, onSelect, setActiveDocumentId, onDeleteNode, renameNode, onDuplicateNode, showDeleteNodeModal, onCreateBillingStatement, billingDocStates, }) => {
6
5
  const [menuOpen, setMenuOpen] = useState(false);
7
6
  const menuRef = useRef(null);
8
7
  const formatTimestamp = (timestamp) => {
@@ -42,11 +41,21 @@ export const InvoiceTableRow = ({ files, row, isSelected, onSelect, setActiveDoc
42
41
  const billingFile = files?.find((file) => file.id === billingDoc?.id);
43
42
  const file = files?.find((file) => file.id === row.id);
44
43
  const hasExportedData = row.exported != null && Boolean(row.exported.timestamp?.trim());
45
- const { onAddFile, onAddFolder, onCopyNode, onDuplicateNode, onMoveNode, onRenameNode, showDeleteNodeModal, } = useDriveContext();
46
- return (_jsxs("tr", { className: "hover:bg-gray-50", children: [_jsx("td", { className: "px-2 py-2", children: _jsx("input", { type: "checkbox", checked: isSelected, onChange: (e) => onSelect(e.target.checked), className: "size-4 rounded border-gray-300 text-blue-600 focus:ring-2 focus:ring-blue-500" }) }), _jsx("td", { className: "py-1 w-10", children: file && (_jsx(FileItem, { fileNode: file, sharingType: "PUBLIC", onRenameNode: onRenameNode, onDuplicateNode: () => new Promise((resolve) => resolve(undefined)), showDeleteNodeModal: showDeleteNodeModal, isAllowedToCreateDocuments: true, className: "h-10", onAddFile: () => new Promise((resolve) => resolve(undefined)), onAddFolder: () => new Promise((resolve) => resolve(undefined)), onCopyNode: () => new Promise((resolve) => resolve(undefined)), onMoveNode: () => new Promise((resolve) => resolve(undefined)), onAddAndSelectNewFolder: () => new Promise((resolve) => resolve(undefined)), getSyncStatusSync: () => undefined, setSelectedNode: () => setActiveDocumentId(row.id) }, row.id)) }), _jsx("td", { className: "px-2 py-2 text-center", children: row.invoiceNo }), _jsx("td", { className: "px-2 py-2 text-center", children: row.issueDate }), _jsx("td", { className: "px-2 py-2 text-center", children: row.dueDate }), _jsx("td", { className: "px-2 py-2 text-center", children: row.currency }), _jsx("td", { className: "px-2 py-2 text-center", children: formatAmount(row.amount) }), (row.status === "ISSUED" ||
44
+ // Wrapper functions for FileItem that convert between nodeId and Node
45
+ const handleRenameNode = async (newName, node) => {
46
+ await renameNode(node.id, newName);
47
+ return undefined;
48
+ };
49
+ const handleDuplicateNode = async (node) => {
50
+ if (onDuplicateNode) {
51
+ await onDuplicateNode(node);
52
+ }
53
+ };
54
+ const handleShowDeleteModal = showDeleteNodeModal || (async () => undefined);
55
+ return (_jsxs("tr", { className: "hover:bg-gray-50", children: [_jsx("td", { className: "px-2 py-2", children: _jsx("input", { type: "checkbox", checked: isSelected, onChange: (e) => onSelect(e.target.checked), className: "size-4 rounded border-gray-300 text-blue-600 focus:ring-2 focus:ring-blue-500" }) }), _jsx("td", { className: "py-1 w-10", children: file && (_jsx(FileItem, { fileNode: file, sharingType: "PUBLIC", onRenameNode: handleRenameNode, onDuplicateNode: handleDuplicateNode, showDeleteNodeModal: handleShowDeleteModal, isAllowedToCreateDocuments: true, className: "h-10", onAddFile: () => new Promise((resolve) => resolve(undefined)), onAddFolder: () => new Promise((resolve) => resolve(undefined)), onCopyNode: () => new Promise((resolve) => resolve(undefined)), onMoveNode: () => new Promise((resolve) => resolve(undefined)), onAddAndSelectNewFolder: () => new Promise((resolve) => resolve(undefined)), getSyncStatusSync: () => undefined, setSelectedNode: () => setActiveDocumentId(row.id) }, row.id)) }), _jsx("td", { className: "px-2 py-2 text-center", children: row.invoiceNo }), _jsx("td", { className: "px-2 py-2 text-center", children: row.issueDate }), _jsx("td", { className: "px-2 py-2 text-center", children: row.dueDate }), _jsx("td", { className: "px-2 py-2 text-center", children: row.currency }), _jsx("td", { className: "px-2 py-2 text-center", children: formatAmount(row.amount) }), (row.status === "ISSUED" ||
47
56
  row.status === "ACCEPTED" ||
48
57
  row.status === "PAYMENTSCHEDULED" ||
49
58
  row.status === "PAYMENTRECEIVED" ||
50
59
  row.status === "PAYMENTSENT") &&
51
- !billingFile && (_jsx("td", { className: "px-2 py-2 text-center", children: _jsx("button", { className: "bg-white border border-gray-300 rounded px-3 py-1 text-sm hover:bg-gray-100 col-span-1 justify-self-end", onClick: () => onCreateBillingStatement?.(row.id), children: "Generate Billing Statement" }) })), billingFile && (_jsx("td", { className: "px-2 py-2 text-center", children: _jsx(FileItem, { fileNode: billingFile, sharingType: "PUBLIC", onRenameNode: onRenameNode, onDuplicateNode: () => new Promise((resolve) => resolve(undefined)), showDeleteNodeModal: showDeleteNodeModal, isAllowedToCreateDocuments: true, className: "h-10", onAddFile: () => new Promise((resolve) => resolve(undefined)), onAddFolder: () => new Promise((resolve) => resolve(undefined)), onCopyNode: () => new Promise((resolve) => resolve(undefined)), onMoveNode: () => new Promise((resolve) => resolve(undefined)), onAddAndSelectNewFolder: () => new Promise((resolve) => resolve(undefined)), getSyncStatusSync: () => undefined, setSelectedNode: () => setActiveDocumentId(billingDoc?.id) }, billingDoc?.id) })), _jsx("td", { className: "px-2 py-2 text-center", children: hasExportedData ? (_jsxs("div", { className: "flex flex-col items-center", children: [_jsx("span", { className: "text-green-500", children: "Yes" }), _jsx("span", { className: "text-green-500 text-xs", children: formatTimestamp(row.exported.timestamp) })] })) : (_jsx("span", { className: "text-red-500", children: "No" })) })] }));
60
+ !billingFile && (_jsx("td", { className: "px-2 py-2 text-center", children: _jsx("button", { className: "bg-white border border-gray-300 rounded px-3 py-1 text-sm hover:bg-gray-100 col-span-1 justify-self-end", onClick: () => onCreateBillingStatement?.(row.id), children: "Generate Billing Statement" }) })), billingFile && (_jsx("td", { className: "px-2 py-2 text-center", children: _jsx(FileItem, { fileNode: billingFile, sharingType: "PUBLIC", onRenameNode: handleRenameNode, onDuplicateNode: handleDuplicateNode, showDeleteNodeModal: handleShowDeleteModal, isAllowedToCreateDocuments: true, className: "h-10", onAddFile: () => new Promise((resolve) => resolve(undefined)), onAddFolder: () => new Promise((resolve) => resolve(undefined)), onCopyNode: () => new Promise((resolve) => resolve(undefined)), onMoveNode: () => new Promise((resolve) => resolve(undefined)), onAddAndSelectNewFolder: () => new Promise((resolve) => resolve(undefined)), getSyncStatusSync: () => undefined, setSelectedNode: () => setActiveDocumentId(billingDoc?.id) }, billingDoc?.id) })), _jsx("td", { className: "px-2 py-2 text-center", children: hasExportedData ? (_jsxs("div", { className: "flex flex-col items-center", children: [_jsx("span", { className: "text-green-500", children: "Yes" }), _jsx("span", { className: "text-green-500 text-xs", children: formatTimestamp(row.exported.timestamp) })] })) : (_jsx("span", { className: "text-red-500", children: "No" })) })] }));
52
61
  };
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/contributor-billing/editor.tsx"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,gCAAgC,CAAC;AAGxC;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,2CAMjD;AAED;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,gBAAgB,2CAarD"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../../editors/contributor-billing/editor.tsx"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,gCAAgC,CAAC;AAIxC;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,2CAMjD;AAKD;;GAEG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,KAAK,EAAE,gBAAgB,2CAWrD"}
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { WagmiContext } from "@powerhousedao/design-system";
3
- import { AnalyticsProvider, DriveContextProvider, useAppConfig, } from "@powerhousedao/reactor-browser";
3
+ import { AnalyticsProvider, useAppConfig, } from "@powerhousedao/reactor-browser";
4
4
  import { DriveExplorer } from "./components/DriveExplorer.js";
5
+ import { withDropZone } from "./utils/withDropZone.js";
5
6
  /**
6
7
  * Base editor component that renders the drive explorer interface.
7
8
  * Customize document opening behavior and drive-level actions here.
@@ -9,6 +10,8 @@ import { DriveExplorer } from "./components/DriveExplorer.js";
9
10
  export function BaseEditor(props) {
10
11
  return (_jsx("div", { className: "new-drive-explorer", style: { height: "100%" }, children: _jsx(DriveExplorer, { ...props }) }));
11
12
  }
13
+ // Wrap base editor with drop zone functionality
14
+ const BaseEditorWithDropZone = withDropZone(BaseEditor);
12
15
  /**
13
16
  * Main editor entry point with required providers.
14
17
  */
@@ -17,5 +20,5 @@ export default function Editor(props) {
17
20
  const analyticsDatabaseName = appConfig?.analyticsDatabaseName;
18
21
  return (
19
22
  // Required context providers for drive functionality
20
- _jsx(DriveContextProvider, { value: props.context, children: _jsx(WagmiContext, { children: _jsx(AnalyticsProvider, { databaseName: analyticsDatabaseName, children: _jsx(BaseEditor, { ...props }) }) }) }));
23
+ _jsx(WagmiContext, { children: _jsx(AnalyticsProvider, { databaseName: analyticsDatabaseName, children: _jsx(BaseEditorWithDropZone, { ...props }) }) }));
21
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../editors/contributor-billing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,eAAO,MAAM,MAAM,EAAE,iBASpB,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../editors/contributor-billing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGxE,eAAO,MAAM,MAAM,EAAE,iBAgBpB,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -7,6 +7,13 @@ export const module = {
7
7
  disableExternalControls: true,
8
8
  documentToolbarEnabled: true,
9
9
  showSwitchboardLink: true,
10
+ documentTypes: [
11
+ "powerhouse/invoice",
12
+ "powerhouse/billing-statement",
13
+ ],
14
+ dragAndDrop: {
15
+ enabled: true,
16
+ },
10
17
  },
11
18
  };
12
19
  export default module;
@@ -0,0 +1,4 @@
1
+ import type { DriveEditorProps } from "@powerhousedao/reactor-browser";
2
+ import type { ComponentType } from "react";
3
+ export declare function withDropZone<T extends DriveEditorProps>(WrappedComponent: ComponentType<T>): ComponentType<T>;
4
+ //# sourceMappingURL=withDropZone.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withDropZone.d.ts","sourceRoot":"","sources":["../../../../editors/contributor-billing/utils/withDropZone.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,gBAAgB,EAEjB,MAAM,gCAAgC,CAAC;AAMxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,wBAAgB,YAAY,CAAC,CAAC,SAAS,gBAAgB,EACrD,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,GACjC,aAAa,CAAC,CAAC,CAAC,CAqClB"}
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { DropZone } from "@powerhousedao/design-system";
3
+ import { setSelectedNode, useOnDropFile, useSelectedDriveId, } from "@powerhousedao/reactor-browser";
4
+ export function withDropZone(WrappedComponent) {
5
+ const WithDropZoneComponent = (props) => {
6
+ const driveId = useSelectedDriveId();
7
+ const onDropFile = useOnDropFile(props.editorConfig?.documentTypes);
8
+ const onAddFile = async (file, parent, onProgress, resolveConflict) => {
9
+ return await onDropFile(file, onProgress, resolveConflict);
10
+ };
11
+ // Only wrap with DropZone if enabled in config
12
+ if (props.editorConfig?.dragAndDrop?.enabled) {
13
+ return (_jsx(DropZone, { onAddFile: onAddFile, setSelectedNode: setSelectedNode, driveId: driveId, useLocalStorage: true, style: { height: "100%" }, children: _jsx(WrappedComponent, { ...props }) }));
14
+ }
15
+ return _jsx(WrappedComponent, { ...props });
16
+ };
17
+ WithDropZoneComponent.displayName = `withDropZone(${WrappedComponent.displayName || WrappedComponent.name || "Component"})`;
18
+ return WithDropZoneComponent;
19
+ }
package/dist/style.css CHANGED
@@ -363,9 +363,6 @@
363
363
  .mt-8 {
364
364
  margin-top: calc(var(--spacing) * 8);
365
365
  }
366
- .mr-1 {
367
- margin-right: calc(var(--spacing) * 1);
368
- }
369
366
  .mr-2 {
370
367
  margin-right: calc(var(--spacing) * 2);
371
368
  }
@@ -375,9 +372,6 @@
375
372
  .mb-2 {
376
373
  margin-bottom: calc(var(--spacing) * 2);
377
374
  }
378
- .mb-3 {
379
- margin-bottom: calc(var(--spacing) * 3);
380
- }
381
375
  .mb-4 {
382
376
  margin-bottom: calc(var(--spacing) * 4);
383
377
  }
@@ -466,9 +460,6 @@
466
460
  .w-4 {
467
461
  width: calc(var(--spacing) * 4);
468
462
  }
469
- .w-5 {
470
- width: calc(var(--spacing) * 5);
471
- }
472
463
  .w-8 {
473
464
  width: calc(var(--spacing) * 8);
474
465
  }
@@ -578,9 +569,6 @@
578
569
  .flex-nowrap {
579
570
  flex-wrap: nowrap;
580
571
  }
581
- .flex-wrap {
582
- flex-wrap: wrap;
583
- }
584
572
  .items-center {
585
573
  align-items: center;
586
574
  }
@@ -605,13 +593,6 @@
605
593
  .gap-4 {
606
594
  gap: calc(var(--spacing) * 4);
607
595
  }
608
- .space-y-1 {
609
- :where(& > :not(:last-child)) {
610
- --tw-space-y-reverse: 0;
611
- margin-block-start: calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));
612
- margin-block-end: calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)));
613
- }
614
- }
615
596
  .space-y-2 {
616
597
  :where(& > :not(:last-child)) {
617
598
  --tw-space-y-reverse: 0;
@@ -684,10 +665,6 @@
684
665
  border-style: var(--tw-border-style);
685
666
  border-width: 1px;
686
667
  }
687
- .border-2 {
688
- border-style: var(--tw-border-style);
689
- border-width: 2px;
690
- }
691
668
  .border-t {
692
669
  border-top-style: var(--tw-border-style);
693
670
  border-top-width: 1px;
@@ -700,10 +677,6 @@
700
677
  border-bottom-style: var(--tw-border-style);
701
678
  border-bottom-width: 2px;
702
679
  }
703
- .border-dashed {
704
- --tw-border-style: dashed;
705
- border-style: dashed;
706
- }
707
680
  .border-blue-100 {
708
681
  border-color: var(--color-blue-100);
709
682
  }
@@ -915,9 +888,6 @@
915
888
  .text-blue-600 {
916
889
  color: var(--color-blue-600);
917
890
  }
918
- .text-blue-800 {
919
- color: var(--color-blue-800);
920
- }
921
891
  .text-blue-900 {
922
892
  color: var(--color-blue-900);
923
893
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powerhousedao/contributor-billing",
3
3
  "description": "Document models that help contributors of open organisations get paid anonymously for their work on a monthly basis.",
4
- "version": "0.0.92",
4
+ "version": "0.0.93",
5
5
  "license": "AGPL-3.0-only",
6
6
  "type": "module",
7
7
  "files": [
@@ -57,10 +57,10 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "@google-cloud/documentai": "^8.12.0",
60
- "@powerhousedao/builder-tools": "^5.0.0-staging.19",
61
- "@powerhousedao/common": "^5.0.0-staging.19",
62
- "@powerhousedao/design-system": "^5.0.0-staging.19",
63
- "@powerhousedao/document-engineering": "^1.37.0",
60
+ "@powerhousedao/builder-tools": "^5.0.0-staging.21",
61
+ "@powerhousedao/common": "^5.0.0-staging.21",
62
+ "@powerhousedao/design-system": "^5.0.0-staging.21",
63
+ "@powerhousedao/document-engineering": "^1.38.0",
64
64
  "@react-pdf/renderer": "^4.3.0",
65
65
  "@safe-global/api-kit": "^3.0.1",
66
66
  "@safe-global/protocol-kit": "^6.0.3",
@@ -69,7 +69,7 @@
69
69
  "@types/cors": "^2.8.17",
70
70
  "axios": "^1.9.0",
71
71
  "cors": "^2.8.5",
72
- "document-model": "^5.0.0-staging.19",
72
+ "document-model": "^5.0.0-staging.21",
73
73
  "dotenv": "^16.5.0",
74
74
  "error": "^10.4.0",
75
75
  "ethers": "^6.14.0",
@@ -85,19 +85,19 @@
85
85
  "@electric-sql/pglite": "^0.2.12",
86
86
  "@eslint/js": "^9.25.0",
87
87
  "@powerhousedao/analytics-engine-core": "^0.5.0",
88
- "@powerhousedao/codegen": "^5.0.0-staging.19",
89
- "@powerhousedao/ph-cli": "^5.0.0-staging.19",
90
- "@powerhousedao/reactor-api": "^5.0.0-staging.19",
91
- "@powerhousedao/reactor-browser": "^5.0.0-staging.19",
92
- "@powerhousedao/reactor-local": "^5.0.0-staging.19",
88
+ "@powerhousedao/codegen": "^5.0.0-staging.21",
89
+ "@powerhousedao/ph-cli": "^5.0.0-staging.21",
90
+ "@powerhousedao/reactor-api": "^5.0.0-staging.21",
91
+ "@powerhousedao/reactor-browser": "^5.0.0-staging.21",
92
+ "@powerhousedao/reactor-local": "^5.0.0-staging.21",
93
93
  "@powerhousedao/scalars": "^1.33.1-staging.5",
94
- "@powerhousedao/switchboard": "^5.0.0-staging.19",
94
+ "@powerhousedao/switchboard": "^5.0.0-staging.21",
95
95
  "@tailwindcss/cli": "^4.1.4",
96
96
  "@testing-library/react": "^16.3.0",
97
97
  "@types/node": "^22.14.1",
98
98
  "@types/react": "^18.3.20",
99
99
  "@vitejs/plugin-react": "^4.4.1",
100
- "document-drive": "^5.0.0-staging.19",
100
+ "document-drive": "^5.0.0-staging.21",
101
101
  "eslint": "^9.25.0",
102
102
  "eslint-plugin-react": "^7.37.5",
103
103
  "eslint-plugin-react-hooks": "^5.2.0",