pacatui 0.1.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +153 -0
  3. package/generated/prisma/browser.ts +59 -0
  4. package/generated/prisma/client.ts +81 -0
  5. package/generated/prisma/commonInputTypes.ts +402 -0
  6. package/generated/prisma/enums.ts +15 -0
  7. package/generated/prisma/internal/class.ts +260 -0
  8. package/generated/prisma/internal/prismaNamespace.ts +1362 -0
  9. package/generated/prisma/internal/prismaNamespaceBrowser.ts +190 -0
  10. package/generated/prisma/models/Customer.ts +1489 -0
  11. package/generated/prisma/models/Invoice.ts +1837 -0
  12. package/generated/prisma/models/Project.ts +1981 -0
  13. package/generated/prisma/models/Setting.ts +1086 -0
  14. package/generated/prisma/models/Tag.ts +1288 -0
  15. package/generated/prisma/models/Task.ts +1669 -0
  16. package/generated/prisma/models/TaskTag.ts +1340 -0
  17. package/generated/prisma/models/TimeEntry.ts +1602 -0
  18. package/generated/prisma/models.ts +19 -0
  19. package/package.json +71 -0
  20. package/prisma/migrations/20260115051911_init/migration.sql +71 -0
  21. package/prisma/migrations/20260115062427_add_time_tracking/migration.sql +20 -0
  22. package/prisma/migrations/20260117233250_add_customers_invoices/migration.sql +81 -0
  23. package/prisma/migrations/migration_lock.toml +3 -0
  24. package/prisma/schema.prisma +162 -0
  25. package/src/App.tsx +1492 -0
  26. package/src/components/CreateInvoiceModal.tsx +222 -0
  27. package/src/components/CustomerModal.tsx +158 -0
  28. package/src/components/CustomerSelectModal.tsx +142 -0
  29. package/src/components/Dashboard.tsx +242 -0
  30. package/src/components/DateTimePicker.tsx +335 -0
  31. package/src/components/EditTimeEntryModal.tsx +293 -0
  32. package/src/components/Header.tsx +65 -0
  33. package/src/components/HelpView.tsx +109 -0
  34. package/src/components/InputModal.tsx +79 -0
  35. package/src/components/InvoicesView.tsx +297 -0
  36. package/src/components/Modal.tsx +38 -0
  37. package/src/components/ProjectList.tsx +114 -0
  38. package/src/components/ProjectModal.tsx +116 -0
  39. package/src/components/SettingsView.tsx +145 -0
  40. package/src/components/SplashScreen.tsx +25 -0
  41. package/src/components/StatusBar.tsx +93 -0
  42. package/src/components/TaskList.tsx +143 -0
  43. package/src/components/Timer.tsx +95 -0
  44. package/src/components/TimerModals.tsx +120 -0
  45. package/src/components/TimesheetView.tsx +218 -0
  46. package/src/components/index.ts +17 -0
  47. package/src/db.ts +629 -0
  48. package/src/hooks/usePaste.ts +69 -0
  49. package/src/index.tsx +75 -0
  50. package/src/stripe.ts +163 -0
  51. package/src/types.ts +361 -0
@@ -0,0 +1,19 @@
1
+
2
+ /* !!! This is code generated by Prisma. Do not edit directly. !!! */
3
+ /* eslint-disable */
4
+ // biome-ignore-all lint: generated file
5
+ // @ts-nocheck
6
+ /*
7
+ * This is a barrel export file for all models and their related types.
8
+ *
9
+ * 🟢 You can import this file directly.
10
+ */
11
+ export type * from './models/Customer.ts'
12
+ export type * from './models/Project.ts'
13
+ export type * from './models/TimeEntry.ts'
14
+ export type * from './models/Invoice.ts'
15
+ export type * from './models/Task.ts'
16
+ export type * from './models/Tag.ts'
17
+ export type * from './models/TaskTag.ts'
18
+ export type * from './models/Setting.ts'
19
+ export type * from './commonInputTypes.ts'
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "pacatui",
3
+ "version": "0.1.0",
4
+ "description": "A simple tui app for task, timer and invoicing for projects.",
5
+ "module": "src/index.tsx",
6
+ "type": "module",
7
+ "private": false,
8
+ "bin": {
9
+ "paca": "./src/index.tsx"
10
+ },
11
+ "files": [
12
+ "src",
13
+ "prisma",
14
+ "generated"
15
+ ],
16
+ "scripts": {
17
+ "start": "bun run src/index.tsx",
18
+ "dev": "bun run --watch src/index.tsx",
19
+ "db:migrate": "bunx prisma migrate dev",
20
+ "db:push": "bunx prisma db push",
21
+ "db:studio": "bunx prisma studio",
22
+ "postinstall": "bunx prisma generate",
23
+ "prepublishOnly": "bunx prisma generate"
24
+ },
25
+ "keywords": [
26
+ "tui",
27
+ "cli",
28
+ "task-manager",
29
+ "todo",
30
+ "project-management",
31
+ "terminal",
32
+ "time-tracking",
33
+ "invoicing",
34
+ "stripe",
35
+ "productivity",
36
+ "timesheet",
37
+ "bun"
38
+ ],
39
+ "author": "Wes Edling",
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/wes/paca.git"
44
+ },
45
+ "homepage": "https://github.com/wes/paca#readme",
46
+ "bugs": {
47
+ "url": "https://github.com/wes/paca/issues"
48
+ },
49
+ "engines": {
50
+ "bun": ">=1.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/bun": "latest",
54
+ "@types/react": "^19.2.8"
55
+ },
56
+ "peerDependencies": {
57
+ "typescript": "^5"
58
+ },
59
+ "dependencies": {
60
+ "@libsql/client": "^0.17.0",
61
+ "@opentui/core": "^0.1.72",
62
+ "@opentui/react": "^0.1.72",
63
+ "@prisma/adapter-better-sqlite3": "^7.2.0",
64
+ "@prisma/adapter-libsql": "^7.2.0",
65
+ "@prisma/client": "^7.2.0",
66
+ "better-sqlite3": "^12.6.0",
67
+ "prisma": "^7.2.0",
68
+ "react": "^19.2.3",
69
+ "stripe": "^20.2.0"
70
+ }
71
+ }
@@ -0,0 +1,71 @@
1
+ -- CreateTable
2
+ CREATE TABLE "Project" (
3
+ "id" TEXT NOT NULL PRIMARY KEY,
4
+ "name" TEXT NOT NULL,
5
+ "description" TEXT,
6
+ "color" TEXT NOT NULL DEFAULT '#3b82f6',
7
+ "archived" BOOLEAN NOT NULL DEFAULT false,
8
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
9
+ "updatedAt" DATETIME NOT NULL
10
+ );
11
+
12
+ -- CreateTable
13
+ CREATE TABLE "Task" (
14
+ "id" TEXT NOT NULL PRIMARY KEY,
15
+ "title" TEXT NOT NULL,
16
+ "description" TEXT,
17
+ "status" TEXT NOT NULL DEFAULT 'todo',
18
+ "priority" TEXT NOT NULL DEFAULT 'medium',
19
+ "dueDate" DATETIME,
20
+ "completedAt" DATETIME,
21
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
22
+ "updatedAt" DATETIME NOT NULL,
23
+ "projectId" TEXT NOT NULL,
24
+ CONSTRAINT "Task_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE CASCADE ON UPDATE CASCADE
25
+ );
26
+
27
+ -- CreateTable
28
+ CREATE TABLE "Tag" (
29
+ "id" TEXT NOT NULL PRIMARY KEY,
30
+ "name" TEXT NOT NULL,
31
+ "color" TEXT NOT NULL DEFAULT '#6b7280',
32
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
33
+ );
34
+
35
+ -- CreateTable
36
+ CREATE TABLE "TaskTag" (
37
+ "taskId" TEXT NOT NULL,
38
+ "tagId" TEXT NOT NULL,
39
+
40
+ PRIMARY KEY ("taskId", "tagId"),
41
+ CONSTRAINT "TaskTag_taskId_fkey" FOREIGN KEY ("taskId") REFERENCES "Task" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
42
+ CONSTRAINT "TaskTag_tagId_fkey" FOREIGN KEY ("tagId") REFERENCES "Tag" ("id") ON DELETE CASCADE ON UPDATE CASCADE
43
+ );
44
+
45
+ -- CreateTable
46
+ CREATE TABLE "Setting" (
47
+ "key" TEXT NOT NULL PRIMARY KEY,
48
+ "value" TEXT NOT NULL,
49
+ "updatedAt" DATETIME NOT NULL
50
+ );
51
+
52
+ -- CreateIndex
53
+ CREATE INDEX "Project_archived_idx" ON "Project"("archived");
54
+
55
+ -- CreateIndex
56
+ CREATE INDEX "Project_createdAt_idx" ON "Project"("createdAt");
57
+
58
+ -- CreateIndex
59
+ CREATE INDEX "Task_projectId_idx" ON "Task"("projectId");
60
+
61
+ -- CreateIndex
62
+ CREATE INDEX "Task_status_idx" ON "Task"("status");
63
+
64
+ -- CreateIndex
65
+ CREATE INDEX "Task_priority_idx" ON "Task"("priority");
66
+
67
+ -- CreateIndex
68
+ CREATE INDEX "Task_dueDate_idx" ON "Task"("dueDate");
69
+
70
+ -- CreateIndex
71
+ CREATE UNIQUE INDEX "Tag_name_key" ON "Tag"("name");
@@ -0,0 +1,20 @@
1
+ -- AlterTable
2
+ ALTER TABLE "Project" ADD COLUMN "hourlyRate" REAL;
3
+
4
+ -- CreateTable
5
+ CREATE TABLE "TimeEntry" (
6
+ "id" TEXT NOT NULL PRIMARY KEY,
7
+ "startTime" DATETIME NOT NULL,
8
+ "endTime" DATETIME,
9
+ "description" TEXT,
10
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
11
+ "updatedAt" DATETIME NOT NULL,
12
+ "projectId" TEXT NOT NULL,
13
+ CONSTRAINT "TimeEntry_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE CASCADE ON UPDATE CASCADE
14
+ );
15
+
16
+ -- CreateIndex
17
+ CREATE INDEX "TimeEntry_projectId_idx" ON "TimeEntry"("projectId");
18
+
19
+ -- CreateIndex
20
+ CREATE INDEX "TimeEntry_startTime_idx" ON "TimeEntry"("startTime");
@@ -0,0 +1,81 @@
1
+ -- CreateTable
2
+ CREATE TABLE "Customer" (
3
+ "id" TEXT NOT NULL PRIMARY KEY,
4
+ "name" TEXT NOT NULL,
5
+ "email" TEXT NOT NULL,
6
+ "stripeCustomerId" TEXT,
7
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
8
+ "updatedAt" DATETIME NOT NULL
9
+ );
10
+
11
+ -- CreateTable
12
+ CREATE TABLE "Invoice" (
13
+ "id" TEXT NOT NULL PRIMARY KEY,
14
+ "stripeInvoiceId" TEXT,
15
+ "status" TEXT NOT NULL DEFAULT 'draft',
16
+ "totalHours" REAL NOT NULL,
17
+ "totalAmount" REAL NOT NULL,
18
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
19
+ "updatedAt" DATETIME NOT NULL,
20
+ "projectId" TEXT NOT NULL,
21
+ "customerId" TEXT NOT NULL,
22
+ CONSTRAINT "Invoice_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
23
+ CONSTRAINT "Invoice_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
24
+ );
25
+
26
+ -- RedefineTables
27
+ PRAGMA defer_foreign_keys=ON;
28
+ PRAGMA foreign_keys=OFF;
29
+ CREATE TABLE "new_Project" (
30
+ "id" TEXT NOT NULL PRIMARY KEY,
31
+ "name" TEXT NOT NULL,
32
+ "description" TEXT,
33
+ "color" TEXT NOT NULL DEFAULT '#3b82f6',
34
+ "hourlyRate" REAL,
35
+ "archived" BOOLEAN NOT NULL DEFAULT false,
36
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
37
+ "updatedAt" DATETIME NOT NULL,
38
+ "customerId" TEXT,
39
+ CONSTRAINT "Project_customerId_fkey" FOREIGN KEY ("customerId") REFERENCES "Customer" ("id") ON DELETE SET NULL ON UPDATE CASCADE
40
+ );
41
+ INSERT INTO "new_Project" ("archived", "color", "createdAt", "description", "hourlyRate", "id", "name", "updatedAt") SELECT "archived", "color", "createdAt", "description", "hourlyRate", "id", "name", "updatedAt" FROM "Project";
42
+ DROP TABLE "Project";
43
+ ALTER TABLE "new_Project" RENAME TO "Project";
44
+ CREATE INDEX "Project_archived_idx" ON "Project"("archived");
45
+ CREATE INDEX "Project_createdAt_idx" ON "Project"("createdAt");
46
+ CREATE INDEX "Project_customerId_idx" ON "Project"("customerId");
47
+ CREATE TABLE "new_TimeEntry" (
48
+ "id" TEXT NOT NULL PRIMARY KEY,
49
+ "startTime" DATETIME NOT NULL,
50
+ "endTime" DATETIME,
51
+ "description" TEXT,
52
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
53
+ "updatedAt" DATETIME NOT NULL,
54
+ "projectId" TEXT NOT NULL,
55
+ "invoiceId" TEXT,
56
+ CONSTRAINT "TimeEntry_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
57
+ CONSTRAINT "TimeEntry_invoiceId_fkey" FOREIGN KEY ("invoiceId") REFERENCES "Invoice" ("id") ON DELETE SET NULL ON UPDATE CASCADE
58
+ );
59
+ INSERT INTO "new_TimeEntry" ("createdAt", "description", "endTime", "id", "projectId", "startTime", "updatedAt") SELECT "createdAt", "description", "endTime", "id", "projectId", "startTime", "updatedAt" FROM "TimeEntry";
60
+ DROP TABLE "TimeEntry";
61
+ ALTER TABLE "new_TimeEntry" RENAME TO "TimeEntry";
62
+ CREATE INDEX "TimeEntry_projectId_idx" ON "TimeEntry"("projectId");
63
+ CREATE INDEX "TimeEntry_startTime_idx" ON "TimeEntry"("startTime");
64
+ CREATE INDEX "TimeEntry_invoiceId_idx" ON "TimeEntry"("invoiceId");
65
+ PRAGMA foreign_keys=ON;
66
+ PRAGMA defer_foreign_keys=OFF;
67
+
68
+ -- CreateIndex
69
+ CREATE UNIQUE INDEX "Customer_email_key" ON "Customer"("email");
70
+
71
+ -- CreateIndex
72
+ CREATE INDEX "Customer_email_idx" ON "Customer"("email");
73
+
74
+ -- CreateIndex
75
+ CREATE INDEX "Invoice_projectId_idx" ON "Invoice"("projectId");
76
+
77
+ -- CreateIndex
78
+ CREATE INDEX "Invoice_customerId_idx" ON "Invoice"("customerId");
79
+
80
+ -- CreateIndex
81
+ CREATE INDEX "Invoice_status_idx" ON "Invoice"("status");
@@ -0,0 +1,3 @@
1
+ # Please do not edit this file manually
2
+ # It should be added in your version-control system (e.g., Git)
3
+ provider = "sqlite"
@@ -0,0 +1,162 @@
1
+ // Paca - Task Manager Database Schema
2
+ // Learn more: https://pris.ly/d/prisma-schema
3
+
4
+ generator client {
5
+ provider = "prisma-client"
6
+ output = "../generated/prisma"
7
+ }
8
+
9
+ datasource db {
10
+ provider = "sqlite"
11
+ }
12
+
13
+ // Customers for invoicing
14
+ model Customer {
15
+ id String @id @default(uuid())
16
+ name String
17
+ email String @unique
18
+ stripeCustomerId String? // Stripe customer ID once created
19
+ createdAt DateTime @default(now())
20
+ updatedAt DateTime @updatedAt
21
+
22
+ // Relations
23
+ projects Project[]
24
+ invoices Invoice[]
25
+
26
+ @@index([email])
27
+ }
28
+
29
+ // Projects are the core organizational unit
30
+ model Project {
31
+ id String @id @default(uuid())
32
+ name String
33
+ description String?
34
+ color String @default("#3b82f6") // Default blue color
35
+ hourlyRate Float? // Hourly rate for billing/tracking
36
+ archived Boolean @default(false)
37
+ createdAt DateTime @default(now())
38
+ updatedAt DateTime @updatedAt
39
+
40
+ // Relations
41
+ tasks Task[]
42
+ timeEntries TimeEntry[]
43
+ customerId String?
44
+ customer Customer? @relation(fields: [customerId], references: [id], onDelete: SetNull)
45
+ invoices Invoice[]
46
+
47
+ // Future: GitHub integration fields
48
+ // githubRepoId String?
49
+ // githubProjectId String?
50
+ // syncEnabled Boolean @default(false)
51
+
52
+ @@index([archived])
53
+ @@index([createdAt])
54
+ @@index([customerId])
55
+ }
56
+
57
+ // Time tracking entries
58
+ model TimeEntry {
59
+ id String @id @default(uuid())
60
+ startTime DateTime
61
+ endTime DateTime?
62
+ description String?
63
+ createdAt DateTime @default(now())
64
+ updatedAt DateTime @updatedAt
65
+
66
+ // Relations
67
+ projectId String
68
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
69
+ invoiceId String?
70
+ invoice Invoice? @relation(fields: [invoiceId], references: [id], onDelete: SetNull)
71
+
72
+ @@index([projectId])
73
+ @@index([startTime])
74
+ @@index([invoiceId])
75
+ }
76
+
77
+ // Invoices for time entries
78
+ model Invoice {
79
+ id String @id @default(uuid())
80
+ stripeInvoiceId String? // Stripe invoice ID once created
81
+ status String @default("draft") // draft, sent, paid
82
+ totalHours Float
83
+ totalAmount Float
84
+ createdAt DateTime @default(now())
85
+ updatedAt DateTime @updatedAt
86
+
87
+ // Relations
88
+ projectId String
89
+ project Project @relation(fields: [projectId], references: [id])
90
+ customerId String
91
+ customer Customer @relation(fields: [customerId], references: [id])
92
+ timeEntries TimeEntry[]
93
+
94
+ @@index([projectId])
95
+ @@index([customerId])
96
+ @@index([status])
97
+ }
98
+
99
+ // Tasks belong to projects
100
+ model Task {
101
+ id String @id @default(uuid())
102
+ title String
103
+ description String?
104
+ status String @default("todo") // todo, in_progress, done
105
+ priority String @default("medium") // low, medium, high, urgent
106
+ dueDate DateTime?
107
+ completedAt DateTime?
108
+ createdAt DateTime @default(now())
109
+ updatedAt DateTime @updatedAt
110
+
111
+ // Relations
112
+ projectId String
113
+ project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
114
+ tags TaskTag[]
115
+
116
+ // Future: GitHub integration fields
117
+ // githubIssueId String?
118
+ // githubIssueNumber Int?
119
+ // syncEnabled Boolean @default(false)
120
+
121
+ @@index([projectId])
122
+ @@index([status])
123
+ @@index([priority])
124
+ @@index([dueDate])
125
+ }
126
+
127
+ // Tags for categorizing tasks
128
+ model Tag {
129
+ id String @id @default(uuid())
130
+ name String @unique
131
+ color String @default("#6b7280") // Default gray
132
+ createdAt DateTime @default(now())
133
+
134
+ // Relations
135
+ tasks TaskTag[]
136
+ }
137
+
138
+ // Many-to-many relation between tasks and tags
139
+ model TaskTag {
140
+ taskId String
141
+ tagId String
142
+ task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
143
+ tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
144
+
145
+ @@id([taskId, tagId])
146
+ }
147
+
148
+ // App settings/preferences
149
+ model Setting {
150
+ key String @id
151
+ value String
152
+ updatedAt DateTime @updatedAt
153
+ }
154
+
155
+ // Future: User model for cloud sync
156
+ // model User {
157
+ // id String @id @default(uuid())
158
+ // email String @unique
159
+ // name String?
160
+ // createdAt DateTime @default(now())
161
+ // lastSyncAt DateTime?
162
+ // }