Skip to content

Commit 461fce4

Browse files
gabrielste1nclaude
andauthored
Referral program (#251)
* feat: added initial oAuth integration setup * fix: show local time not utc, add link to platform.openai * feat: add complete cleanup script and troubleshooting docs - Add automated uninstall script for complete system cleanup - Add detailed cleanup instructions with manual steps - Add comprehensive troubleshooting guide for common issues - Fix architecture mismatch documentation (ARM64 vs x64) - Document proper macOS permission reset using tccutil - Resolve environment contamination between production and dev Fixes issues with: - better-sqlite3 architecture mismatch on Apple Silicon - Database/settings conflicts between DMG and dev mode - Microphone printing 'you' instead of transcription - Node running under Rosetta emulation * chore: update lockfile * fix: register hotkey immediately after step * chore: version bump * refactor: migration to neon auth * refactor: make sure to use own UI components * refactor: ui overhaul * refactor: replace IPC-based OAuth callback with deep-link flow, add main-process session clearing for sign-out, and remove GitHub social provider * feat: add skills * feat: ignore claude skills and agents * feat: add OpenWhispr cloud transcription with usage tracking, limits, and session refresh * refactor: Fix cloud transcription binary handling, add auth state sync, clean up debug logging * feat: Show UpgradePrompt dialog in ControlPanel when daily transcription limit is reached * feat: add AssemblyAI real-time streaming transcription with WebSocket pre-warming and mic caching for instant-start recording * fix: streaming handling when no api key * fix: persist AI provider selection to localStorage so Custom/Local tabs don't reset to OpenAI on settings reopen * chore: version bump * refactor: onboarding style refactor * feat: Add Stripe billing with trial support, refactor duplicate API handlers for DRY, migrate to weekly usage limits, and enhance auth flow with user existence check * feat: complete OAuth flow with branded redirect, UI refinements, code quality improvements * fix: ui polish * refactor: consolidate session refresh logic with withSessionRefresh utility, streamline onboarding flow for signed-in users, and persist permission states * chore: update .gitignore * feat(ui): add ReferralDashboard component with full referral UI ReferralDashboard.tsx: - Dashboard tab with stats cards (referrals, pending, converted, months earned) - Gift card preview showing referral reward - Invite tab with email input and send functionality - History tabs showing referrals and sent invites - Copy-to-clipboard for referral link - Loading, error, and empty states - Toast notifications for user feedback Settings integration: - Add Referrals section to SettingsModal sidebar - Add referrals case to SettingsPage section renderer Design: - Follows OpenWhispr design language - Uses existing UI components (Button, Badge, Input, Tabs) - Proper TypeScript typing throughout Co-Authored-By: Claude Opus 4.5 <[email protected]> * feat(ipc): add referral IPC handlers and type definitions IPC Handlers (ipcHandlers.js): - get-referral-stats: fetch user's referral dashboard data - send-referral-invite: send email invitation via API - get-referral-invites: list sent invitations - Proper cookie forwarding for authentication - Error handling consistent with other cloud handlers Preload (preload.js): - Expose getReferralStats, sendReferralInvite, getReferralInvites Types (electron.ts): - ReferralStats interface with proper union types for status - ReferralInvite interface for email invitations - Type-safe method signatures Co-Authored-By: Claude Opus 4.5 <[email protected]> * chore: update dependencies Co-Authored-By: Claude Opus 4.5 <[email protected]> * feat: Add sidebar navigation, notes system, and dictionary view * feat: referral card redesign * fix: neon auth build config --------- Co-authored-by: Claude Opus 4.5 <[email protected]>
1 parent 77ac47a commit 461fce4

32 files changed

+3769
-418
lines changed

main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ function navigateControlPanelWithVerifier(verifier) {
320320
windowManager.controlPanelWindow.focus();
321321
}
322322

323+
323324
function handleOAuthDeepLink(deepLinkUrl) {
324325
try {
325326
const parsed = new URL(deepLinkUrl);

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"vite": "^6.3.5"
8484
},
8585
"dependencies": {
86+
"@neondatabase/auth": "^0.1.0-beta.21",
8687
"@neondatabase/neon-js": "^0.1.0-beta.22",
8788
"@radix-ui/react-accordion": "^1.1.2",
8889
"@radix-ui/react-dialog": "^1.1.14",

preload.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { contextBridge, ipcRenderer } = require("electron");
1+
const { contextBridge, ipcRenderer, webUtils } = require("electron");
22

33
/**
44
* Helper to register an IPC listener and return a cleanup function.
@@ -51,6 +51,37 @@ contextBridge.exposeInMainWorld("electronAPI", {
5151
getDictionary: () => ipcRenderer.invoke("db-get-dictionary"),
5252
setDictionary: (words) => ipcRenderer.invoke("db-set-dictionary", words),
5353

54+
// Note functions
55+
saveNote: (title, content, noteType, sourceFile, audioDuration) =>
56+
ipcRenderer.invoke("db-save-note", title, content, noteType, sourceFile, audioDuration),
57+
getNote: (id) => ipcRenderer.invoke("db-get-note", id),
58+
getNotes: (noteType, limit) => ipcRenderer.invoke("db-get-notes", noteType, limit),
59+
updateNote: (id, updates) => ipcRenderer.invoke("db-update-note", id, updates),
60+
deleteNote: (id) => ipcRenderer.invoke("db-delete-note", id),
61+
exportNote: (noteId, format) => ipcRenderer.invoke("export-note", noteId, format),
62+
63+
// Audio file operations
64+
selectAudioFile: () => ipcRenderer.invoke("select-audio-file"),
65+
transcribeAudioFile: (filePath, options) =>
66+
ipcRenderer.invoke("transcribe-audio-file", filePath, options),
67+
getPathForFile: (file) => webUtils.getPathForFile(file),
68+
69+
onNoteAdded: (callback) => {
70+
const listener = (_event, note) => callback?.(note);
71+
ipcRenderer.on("note-added", listener);
72+
return () => ipcRenderer.removeListener("note-added", listener);
73+
},
74+
onNoteUpdated: (callback) => {
75+
const listener = (_event, note) => callback?.(note);
76+
ipcRenderer.on("note-updated", listener);
77+
return () => ipcRenderer.removeListener("note-updated", listener);
78+
},
79+
onNoteDeleted: (callback) => {
80+
const listener = (_event, data) => callback?.(data);
81+
ipcRenderer.on("note-deleted", listener);
82+
return () => ipcRenderer.removeListener("note-deleted", listener);
83+
},
84+
5485
onTranscriptionAdded: (callback) => {
5586
const listener = (_event, transcription) => callback?.(transcription);
5687
ipcRenderer.on("transcription-added", listener);
@@ -256,6 +287,11 @@ contextBridge.exposeInMainWorld("electronAPI", {
256287
cloudCheckout: () => ipcRenderer.invoke("cloud-checkout"),
257288
cloudBillingPortal: () => ipcRenderer.invoke("cloud-billing-portal"),
258289

290+
// Referral stats
291+
getReferralStats: () => ipcRenderer.invoke("get-referral-stats"),
292+
sendReferralInvite: (email) => ipcRenderer.invoke("send-referral-invite", email),
293+
getReferralInvites: () => ipcRenderer.invoke("get-referral-invites"),
294+
259295
// Assembly AI Streaming
260296
assemblyAiStreamingWarmup: (options) => ipcRenderer.invoke("assemblyai-streaming-warmup", options),
261297
assemblyAiStreamingStart: (options) => ipcRenderer.invoke("assemblyai-streaming-start", options),

0 commit comments

Comments
 (0)