Skip to content

Commit

Permalink
fix: resolve typescript issues and update request-invoice-web depende…
Browse files Browse the repository at this point in the history
…ncies (#14)

* fix: resolve typescript issues

- Update ExtendedInvoice interface to use sellerInfo instead of businessInfo
- Fix BusinessAgent usage in use-business-agent hook
- Add ensureHyperscrollDir implementation in preload.ts

Co-Authored-By: ben <ben@prologe.io>

* fix: update React/Next.js versions and replace Geist with Inter font

Co-Authored-By: ben <ben@prologe.io>

* chore: update TypeScript configuration for Next.js 13.4

Co-Authored-By: ben <ben@prologe.io>

* fix: preload issue

* feat: hide not finished agents + add request logo

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ben <ben@prologe.io>
  • Loading branch information
1 parent 50f96ff commit b1f21b4
Show file tree
Hide file tree
Showing 23 changed files with 9,485 additions and 7,942 deletions.
6 changes: 3 additions & 3 deletions .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ Assistant Guidelines:

Project Structure:
- Main app is in packages/desktop
- Frontend: packages/desktop/src/renderer
- Backend: packages/desktop/src/electron
- packages/landing-v0 containts landing page and in the future all account logins and signups
- Frontend: packages/desktop/src/renderer (vite)
- Backend: packages/desktop/src/electron (electron)
- packages/landing-v0 containts landing page and in the future all account logins and signups (nextjs app dir)



Expand Down
15 changes: 14 additions & 1 deletion packages/desktop/electron/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -701,4 +701,17 @@ ipcMain.handle('file:open-in-obsidian', async (_, filePath: string) => {
console.error('Failed to open in Obsidian:', error);
throw error;
}
});
});

// Add this with your other IPC handlers
ipcMain.handle('ensure-hyperscroll-dir', async () => {
const hyperscrollDir = path.join(os.homedir(), 'Hyperscroll');
try {
await fs.mkdir(hyperscrollDir, { recursive: true });
return hyperscrollDir;
} catch (error) {
console.error('Failed to ensure Hyperscroll directory:', error);
throw error;
}
});

8 changes: 8 additions & 0 deletions packages/desktop/electron/preload.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { contextBridge, ipcRenderer, IpcRendererEvent, shell } from 'electron';
import type { VaultConfig, FileInfo, MarkdownContent, ElectronAPI, ICreateRequestParameters } from '../src/types/electron';

const debug = (...args: any[]) => {
console.log('[Preload]', ...args);
};
Expand Down Expand Up @@ -328,6 +329,13 @@ const api: ElectronAPI = {
openInObsidian: async (filePath: string) => {
debug('Opening file in Obsidian:', filePath);
return ipcRenderer.invoke('file:open-in-obsidian', filePath);
},

// Hyperscroll Directory Management
ensureHyperscrollDir: async () => {
debug('Ensuring Hyperscroll directory exists');
const hyperscrollDir = await ipcRenderer.invoke('ensure-hyperscroll-dir');
return hyperscrollDir;
}
} satisfies ElectronAPI;

Expand Down
12 changes: 10 additions & 2 deletions packages/desktop/src/agents/add-to-mac-calendar-agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -302,10 +302,18 @@ const AddToCalendarUI: React.FC<AddToCalendarUIProps> = ({

export const AddToMacCalendarAgent: Agent = {
id: 'add-to-mac-calendar',
name: 'Add to Calendar',
description: 'Creates calendar events from detected content',
name: 'Calendar Manager',
description: 'Automatically adds events to your Mac calendar',
type: 'event' as AgentType,
isActive: true,
isReady: false,
miniApp: () => <AddToCalendarUI context={{
id: 'preview',
title: 'Calendar Preview',
vitalInformation: '',
type: 'event',
source: 'preview'
}} />,

eventAction(context: RecognizedContext, onSuccess?: () => void): React.ReactNode {
return <AddToCalendarUI context={context} onSuccess={onSuccess} />;
Expand Down
7 changes: 5 additions & 2 deletions packages/desktop/src/agents/base-agent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ReactNode } from 'react';
import { RecognizedContext } from '@/components/event-classification';

export type AgentType = 'invoice' | 'calendar' | 'task' | 'event' | 'goal';
export type AgentType = 'task' | 'event' | 'invoice' | 'goal' | 'business';

export interface RecognizedContext {
id: string;
Expand All @@ -13,11 +14,13 @@ export interface RecognizedContext {
export interface Agent {
id: string;
name: string;
displayName?: () => ReactNode;
description: string;
type: AgentType;
isActive: boolean;
eventAction: (context: RecognizedContext, onSuccess?: () => void) => ReactNode;
isReady: boolean;
miniApp?: () => ReactNode;
eventAction(context: RecognizedContext, onSuccess?: () => void): ReactNode;
}

export interface ClassificationResult {
Expand Down
1 change: 1 addition & 0 deletions packages/desktop/src/agents/business-agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ export const BusinessAgent: Agent = {
description: 'Automatically processes and stores business-related information from your screen content',
type: 'business' as AgentType,
isActive: true,
isReady: false,
miniApp: () => <BusinessInfoView />,

eventAction(context: RecognizedContext, onSuccess?: () => void): React.ReactNode {
Expand Down
10 changes: 5 additions & 5 deletions packages/desktop/src/agents/goal-planning-agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -351,14 +351,14 @@ const GoalPlanningDashboard: React.FC = () => {

export const GoalPlanningAgent: Agent = {
id: 'goal-planning',
name: 'Goal Planning',
description: 'Analyzes markdown files to extract and track goals',
name: 'Goal Planner',
description: 'Helps you track and manage your goals and objectives',
type: 'goal' as AgentType,
isActive: true,

isReady: false,
miniApp: () => <GoalPlanningDashboard />,

eventAction(context: RecognizedContext, onSuccess?: () => void): React.ReactNode {
return <GoalPlanningUI context={context} onSuccess={onSuccess} />;
},

miniApp: () => <GoalPlanningDashboard />,
};
140 changes: 80 additions & 60 deletions packages/desktop/src/agents/invoice-agent.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { Agent, RecognizedContext, AgentType } from './base-agent';
import * as React from 'react';
import { Button } from '../components/ui/button';
import {
Dialog,
DialogContent,
DialogTrigger,
} from '@/components/ui/dialog';
import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog';
import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import requestLogo from '@/assets/request-req-logo.png';
import {
Table,
TableBody,
Expand All @@ -27,8 +24,8 @@ interface BusinessInfo extends Omit<ActorInfo, 'miscellaneous'> {
miscellaneous?: Record<string, unknown>;
}

interface ExtendedInvoice extends Omit<Invoice, 'businessInfo' | 'buyerInfo'> {
businessInfo: BusinessInfo;
interface ExtendedInvoice extends Omit<Invoice, 'sellerInfo' | 'buyerInfo'> {
sellerInfo: BusinessInfo;
buyerInfo?: BusinessInfo;
}

Expand All @@ -41,6 +38,16 @@ interface InvoiceAgentUIProps {
onSuccess?: () => void;
}

const RequestLogo = ({ className }: { className?: string }) => (
<img
src={requestLogo}
alt="Request Network"
width={20}
height={20}
className={className}
/>
);

const InvoiceAgentUI: React.FC<InvoiceAgentUIProps> = ({
context,
onSuccess,
Expand All @@ -53,7 +60,7 @@ const InvoiceAgentUI: React.FC<InvoiceAgentUIProps> = ({
if (open && !result && !isProcessing) {
console.log('0xHypr', 'Modal opened, starting invoice processing', {
contextId: context.id,
vitalInfo: context.vitalInformation
vitalInfo: context.vitalInformation,
});
processInvoice(context.vitalInformation);
}
Expand All @@ -68,52 +75,57 @@ const InvoiceAgentUI: React.FC<InvoiceAgentUIProps> = ({
return undefined;
}

const invoice = result.data.invoice;
const invoice = result.data.invoice as ExtendedInvoice;
console.log('0xHypr', 'Transforming invoice data:', invoice);

// Transform buyerInfo to ensure miscellaneous is a Record<string, unknown>
const transformedBuyerInfo: BusinessInfo | undefined = invoice.buyerInfo ? {
businessName: invoice.buyerInfo.businessName || '',
email: invoice.buyerInfo.email,
firstName: invoice.buyerInfo.firstName,
lastName: invoice.buyerInfo.lastName,
phone: invoice.buyerInfo.phone,
address: invoice.buyerInfo.address,
taxRegistration: invoice.buyerInfo.taxRegistration,
miscellaneous: {},
} : undefined;
const transformedBuyerInfo: BusinessInfo | undefined = invoice.buyerInfo
? {
businessName: invoice.buyerInfo.businessName || '',
email: invoice.buyerInfo.email,
firstName: invoice.buyerInfo.firstName,
lastName: invoice.buyerInfo.lastName,
phone: invoice.buyerInfo.phone,
address: invoice.buyerInfo.address,
taxRegistration: invoice.buyerInfo.taxRegistration,
miscellaneous: {},
}
: undefined;

const transformedValues: Partial<ExtendedInvoice> = {
businessInfo: {
businessName: invoice.buyerInfo?.businessName || '',
email: invoice.buyerInfo?.email,
firstName: invoice.buyerInfo?.firstName,
lastName: invoice.buyerInfo?.lastName,
phone: invoice.buyerInfo?.phone,
address: invoice.buyerInfo?.address,
taxRegistration: invoice.buyerInfo?.taxRegistration,
miscellaneous: {},
sellerInfo: {
businessName: invoice.sellerInfo?.businessName || '',
email: invoice.sellerInfo?.email || '',
firstName: invoice.sellerInfo?.firstName || '',
lastName: invoice.sellerInfo?.lastName || '',
phone: invoice.sellerInfo?.phone || '',
address: invoice.sellerInfo?.address || {},
taxRegistration: invoice.sellerInfo?.taxRegistration || '',
miscellaneous: invoice.sellerInfo?.miscellaneous || {},
},
buyerInfo: transformedBuyerInfo,
invoiceItems: invoice.invoiceItems?.map(item => ({
name: item.name || 'Untitled Item',
quantity: item.quantity || 1,
unitPrice: item.unitPrice || '0',
currency: item.currency || 'ETH',
tax: {
type: item.tax?.type || 'percentage',
amount: item.tax?.amount || '0'
},
reference: item.reference || '',
deliveryDate: item.deliveryDate || new Date().toISOString(),
deliveryPeriod: item.deliveryPeriod || '',
})) || [],
paymentTerms: invoice.paymentTerms ? {
dueDate: invoice.paymentTerms.dueDate,
lateFeesPercent: invoice.paymentTerms.lateFeesPercent,
lateFeesFix: invoice.paymentTerms.lateFeesFix,
miscellaneous: {},
} as ExtendedPaymentTerms : undefined,
invoiceItems:
invoice.invoiceItems?.map((item) => ({
name: item.name || 'Untitled Item',
quantity: item.quantity || 1,
unitPrice: item.unitPrice || '0',
currency: item.currency || 'ETH',
tax: {
type: item.tax?.type || 'percentage',
amount: item.tax?.amount || '0',
},
reference: item.reference || '',
deliveryDate: item.deliveryDate || new Date().toISOString(),
deliveryPeriod: item.deliveryPeriod || '',
})) || [],
paymentTerms: invoice.paymentTerms
? ({
dueDate: invoice.paymentTerms.dueDate,
lateFeesPercent: invoice.paymentTerms.lateFeesPercent,
lateFeesFix: invoice.paymentTerms.lateFeesFix,
miscellaneous: {},
} as ExtendedPaymentTerms)
: undefined,
note: invoice.note || '',
terms: invoice.terms || '',
purchaseOrderId: invoice.purchaseOrderId,
Expand All @@ -128,7 +140,7 @@ const InvoiceAgentUI: React.FC<InvoiceAgentUIProps> = ({
from: open,
to: newOpen,
hasResult: !!result,
isProcessing
isProcessing,
});
setOpen(newOpen);
};
Expand All @@ -142,15 +154,15 @@ const InvoiceAgentUI: React.FC<InvoiceAgentUIProps> = ({
return (
<div className="flex items-center justify-between p-4 border-b">
<div className="flex flex-col">
<h3 className="font-medium">Invoice Request</h3>
<div className="flex items-center gap-2">
<h3 className="font-medium">Invoice Request</h3>
<RequestLogo className="opacity-80" />
</div>
<p className="text-sm text-muted-foreground">{context.title}</p>
</div>
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogTrigger asChild>
<Button
variant="outline"
disabled={isProcessing}
>
<Button variant="outline" disabled={isProcessing}>
{isProcessing ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Expand Down Expand Up @@ -243,9 +255,7 @@ const RequestsView: React.FC = () => {
{request.amount} {request.currency.value}
</TableCell>
<TableCell>{request.status}</TableCell>
<TableCell>
{request.payer?.value || 'No recipient'}
</TableCell>
<TableCell>{request.payer?.value || 'No recipient'}</TableCell>
</TableRow>
))}
</TableBody>
Expand All @@ -255,15 +265,25 @@ const RequestsView: React.FC = () => {
};

export const InvoiceAgent: Agent = {
id: 'request-network-agent',
name: 'Automatically Create Request Network Invoice',
id: 'invoice-agent',
name: 'Invoice Manager',
displayName: () => (
<div className="flex items-center gap-2">
<RequestLogo />
Invoice Manager
</div>
),
description:
'Automatically creates invoices for your workflow based on your screen content',
'Automatically processes and creates invoices from detected content',
type: 'invoice' as AgentType,
isActive: true,
isReady: true,
miniApp: () => <RequestsView />,

eventAction(context: RecognizedContext, onSuccess?: () => void): React.ReactNode {
eventAction(
context: RecognizedContext,
onSuccess?: () => void
): React.ReactNode {
return <InvoiceAgentUI context={context} onSuccess={onSuccess} />;
},
};
5 changes: 3 additions & 2 deletions packages/desktop/src/agents/task-agent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -506,10 +506,11 @@ const TaskDashboardView: React.FC = () => {

export const AddTaskToObsidianAgent: Agent = {
id: 'add-task-to-obsidian',
name: 'Add Task to Obsidian',
description: 'Creates tasks in your Obsidian vault from detected content',
name: 'Task Manager',
description: 'Automatically adds tasks to your Obsidian vault',
type: 'task' as AgentType,
isActive: true,
isReady: false,
miniApp: () => <TaskDashboardView />,

eventAction(context: RecognizedContext, onSuccess?: () => void): React.ReactNode {
Expand Down
Binary file added packages/desktop/src/assets/request-req-logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit b1f21b4

Please sign in to comment.