@realtimex/email-automator 2.2.0 → 2.2.1
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.
- package/api/server.ts +0 -6
- package/api/src/config/index.ts +3 -0
- package/bin/email-automator-setup.js +2 -3
- package/bin/email-automator.js +23 -7
- package/package.json +1 -2
- package/src/App.tsx +0 -622
- package/src/components/AccountSettings.tsx +0 -310
- package/src/components/AccountSettingsPage.tsx +0 -390
- package/src/components/Configuration.tsx +0 -1345
- package/src/components/Dashboard.tsx +0 -940
- package/src/components/ErrorBoundary.tsx +0 -71
- package/src/components/LiveTerminal.tsx +0 -308
- package/src/components/LoadingSpinner.tsx +0 -39
- package/src/components/Login.tsx +0 -371
- package/src/components/Logo.tsx +0 -57
- package/src/components/SetupWizard.tsx +0 -388
- package/src/components/Toast.tsx +0 -109
- package/src/components/migration/MigrationBanner.tsx +0 -97
- package/src/components/migration/MigrationModal.tsx +0 -458
- package/src/components/migration/MigrationPulseIndicator.tsx +0 -38
- package/src/components/mode-toggle.tsx +0 -24
- package/src/components/theme-provider.tsx +0 -72
- package/src/components/ui/alert.tsx +0 -66
- package/src/components/ui/button.tsx +0 -57
- package/src/components/ui/card.tsx +0 -75
- package/src/components/ui/dialog.tsx +0 -133
- package/src/components/ui/input.tsx +0 -22
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/otp-input.tsx +0 -184
- package/src/context/AppContext.tsx +0 -422
- package/src/context/MigrationContext.tsx +0 -53
- package/src/context/TerminalContext.tsx +0 -31
- package/src/core/actions.ts +0 -76
- package/src/core/auth.ts +0 -108
- package/src/core/intelligence.ts +0 -76
- package/src/core/processor.ts +0 -112
- package/src/hooks/useRealtimeEmails.ts +0 -111
- package/src/index.css +0 -140
- package/src/lib/api-config.ts +0 -42
- package/src/lib/api-old.ts +0 -228
- package/src/lib/api.ts +0 -421
- package/src/lib/migration-check.ts +0 -264
- package/src/lib/sounds.ts +0 -120
- package/src/lib/supabase-config.ts +0 -117
- package/src/lib/supabase.ts +0 -28
- package/src/lib/types.ts +0 -166
- package/src/lib/utils.ts +0 -6
- package/src/main.tsx +0 -10
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import { Mail, Cloud, Key, Link as LinkIcon, Loader2, CheckCircle, XCircle } from 'lucide-react';
|
|
3
|
-
import { supabase } from '../lib/supabase';
|
|
4
|
-
|
|
5
|
-
interface AccountStatus {
|
|
6
|
-
gmail: boolean;
|
|
7
|
-
m365: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function AccountSettings() {
|
|
11
|
-
const [status, setStatus] = useState<AccountStatus>({ gmail: false, m365: false });
|
|
12
|
-
const [loading, setLoading] = useState(true);
|
|
13
|
-
const [showGmailDialog, setShowGmailDialog] = useState(false);
|
|
14
|
-
const [showM365Dialog, setShowM365Dialog] = useState(false);
|
|
15
|
-
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
checkAccountStatus();
|
|
18
|
-
}, []);
|
|
19
|
-
|
|
20
|
-
async function checkAccountStatus() {
|
|
21
|
-
setLoading(true);
|
|
22
|
-
const { data } = await supabase
|
|
23
|
-
.from('email_accounts')
|
|
24
|
-
.select('provider')
|
|
25
|
-
.eq('user_id', (await supabase.auth.getUser()).data.user?.id);
|
|
26
|
-
|
|
27
|
-
const providers = data?.map(a => a.provider) || [];
|
|
28
|
-
setStatus({
|
|
29
|
-
gmail: providers.includes('gmail'),
|
|
30
|
-
m365: providers.includes('m365')
|
|
31
|
-
});
|
|
32
|
-
setLoading(false);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<div className="space-y-6">
|
|
37
|
-
<h2 className="text-2xl font-bold text-slate-900">Email Accounts</h2>
|
|
38
|
-
<p className="text-slate-600">Connect your email providers to start automating</p>
|
|
39
|
-
|
|
40
|
-
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
41
|
-
{/* Gmail Card */}
|
|
42
|
-
<div className="bg-white rounded-2xl border-l-4 border-l-red-500 p-6 shadow-sm">
|
|
43
|
-
<div className="flex justify-between items-start mb-4">
|
|
44
|
-
<div className="flex items-center gap-3">
|
|
45
|
-
<Mail className="w-6 h-6 text-red-500" />
|
|
46
|
-
<h3 className="text-lg font-bold">Gmail</h3>
|
|
47
|
-
</div>
|
|
48
|
-
{status.gmail ? (
|
|
49
|
-
<span className="px-3 py-1 bg-emerald-50 text-emerald-700 rounded-full text-xs font-semibold flex items-center gap-1">
|
|
50
|
-
<CheckCircle className="w-3 h-3" />
|
|
51
|
-
Connected
|
|
52
|
-
</span>
|
|
53
|
-
) : (
|
|
54
|
-
<span className="px-3 py-1 bg-slate-100 text-slate-600 rounded-full text-xs font-semibold flex items-center gap-1">
|
|
55
|
-
<XCircle className="w-3 h-3" />
|
|
56
|
-
Disconnected
|
|
57
|
-
</span>
|
|
58
|
-
)}
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<button
|
|
62
|
-
onClick={() => setShowGmailDialog(true)}
|
|
63
|
-
className="w-full bg-red-50 hover:bg-red-100 text-red-600 py-2 rounded-xl font-medium transition-all flex items-center justify-center gap-2"
|
|
64
|
-
>
|
|
65
|
-
<LinkIcon className="w-4 h-4" />
|
|
66
|
-
{status.gmail ? 'Reconnect' : 'Connect Gmail'}
|
|
67
|
-
</button>
|
|
68
|
-
|
|
69
|
-
<details className="mt-4">
|
|
70
|
-
<summary className="cursor-pointer text-sm text-slate-600 hover:text-slate-900 flex items-center gap-2">
|
|
71
|
-
<Key className="w-4 h-4" />
|
|
72
|
-
Configure Credentials
|
|
73
|
-
</summary>
|
|
74
|
-
<div className="mt-3 space-y-2">
|
|
75
|
-
<p className="text-xs text-slate-500">Paste your Google OAuth credentials JSON:</p>
|
|
76
|
-
<textarea
|
|
77
|
-
className="w-full p-2 border rounded-lg text-xs font-mono"
|
|
78
|
-
rows={4}
|
|
79
|
-
placeholder='{"installed": {"client_id": "...", ...}}'
|
|
80
|
-
/>
|
|
81
|
-
<button className="w-full bg-slate-100 hover:bg-slate-200 text-slate-700 py-1 rounded-lg text-sm">
|
|
82
|
-
Save Credentials
|
|
83
|
-
</button>
|
|
84
|
-
</div>
|
|
85
|
-
</details>
|
|
86
|
-
</div>
|
|
87
|
-
|
|
88
|
-
{/* Microsoft 365 Card */}
|
|
89
|
-
<div className="bg-white rounded-2xl border-l-4 border-l-blue-500 p-6 shadow-sm">
|
|
90
|
-
<div className="flex justify-between items-start mb-4">
|
|
91
|
-
<div className="flex items-center gap-3">
|
|
92
|
-
<Cloud className="w-6 h-6 text-blue-500" />
|
|
93
|
-
<h3 className="text-lg font-bold">Microsoft 365</h3>
|
|
94
|
-
</div>
|
|
95
|
-
{status.m365 ? (
|
|
96
|
-
<span className="px-3 py-1 bg-emerald-50 text-emerald-700 rounded-full text-xs font-semibold flex items-center gap-1">
|
|
97
|
-
<CheckCircle className="w-3 h-3" />
|
|
98
|
-
Connected
|
|
99
|
-
</span>
|
|
100
|
-
) : (
|
|
101
|
-
<span className="px-3 py-1 bg-slate-100 text-slate-600 rounded-full text-xs font-semibold flex items-center gap-1">
|
|
102
|
-
<XCircle className="w-3 h-3" />
|
|
103
|
-
Disconnected
|
|
104
|
-
</span>
|
|
105
|
-
)}
|
|
106
|
-
</div>
|
|
107
|
-
|
|
108
|
-
<button
|
|
109
|
-
onClick={() => setShowM365Dialog(true)}
|
|
110
|
-
className="w-full bg-blue-50 hover:bg-blue-100 text-blue-600 py-2 rounded-xl font-medium transition-all flex items-center justify-center gap-2"
|
|
111
|
-
>
|
|
112
|
-
<LinkIcon className="w-4 h-4" />
|
|
113
|
-
{status.m365 ? 'Reconnect' : 'Connect M365'}
|
|
114
|
-
</button>
|
|
115
|
-
|
|
116
|
-
<details className="mt-4">
|
|
117
|
-
<summary className="cursor-pointer text-sm text-slate-600 hover:text-slate-900 flex items-center gap-2">
|
|
118
|
-
<Key className="w-4 h-4" />
|
|
119
|
-
Configure Client
|
|
120
|
-
</summary>
|
|
121
|
-
<div className="mt-3 space-y-2">
|
|
122
|
-
<p className="text-xs text-slate-500">Paste your Azure AD app config JSON:</p>
|
|
123
|
-
<textarea
|
|
124
|
-
className="w-full p-2 border rounded-lg text-xs font-mono"
|
|
125
|
-
rows={4}
|
|
126
|
-
placeholder='{"client_id": "...", "tenant_id": "..."}'
|
|
127
|
-
/>
|
|
128
|
-
<button className="w-full bg-slate-100 hover:bg-slate-200 text-slate-700 py-1 rounded-lg text-sm">
|
|
129
|
-
Save Config
|
|
130
|
-
</button>
|
|
131
|
-
</div>
|
|
132
|
-
</details>
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
|
|
136
|
-
{/* Gmail Auth Dialog */}
|
|
137
|
-
{showGmailDialog && (
|
|
138
|
-
<GmailAuthDialog onClose={() => {
|
|
139
|
-
setShowGmailDialog(false);
|
|
140
|
-
checkAccountStatus();
|
|
141
|
-
}} />
|
|
142
|
-
)}
|
|
143
|
-
|
|
144
|
-
{/* M365 Auth Dialog */}
|
|
145
|
-
{showM365Dialog && (
|
|
146
|
-
<M365AuthDialog onClose={() => {
|
|
147
|
-
setShowM365Dialog(false);
|
|
148
|
-
checkAccountStatus();
|
|
149
|
-
}} />
|
|
150
|
-
)}
|
|
151
|
-
</div>
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function GmailAuthDialog({ onClose }: { onClose: () => void }) {
|
|
156
|
-
const [authUrl, setAuthUrl] = useState('');
|
|
157
|
-
const [code, setCode] = useState('');
|
|
158
|
-
const [loading, setLoading] = useState(true);
|
|
159
|
-
|
|
160
|
-
useEffect(() => {
|
|
161
|
-
fetchAuthUrl();
|
|
162
|
-
}, []);
|
|
163
|
-
|
|
164
|
-
async function fetchAuthUrl() {
|
|
165
|
-
try {
|
|
166
|
-
const res = await fetch('http://localhost:3002/api/auth/gmail/url');
|
|
167
|
-
const data = await res.json();
|
|
168
|
-
setAuthUrl(data.url);
|
|
169
|
-
} catch (error) {
|
|
170
|
-
console.error(error);
|
|
171
|
-
} finally {
|
|
172
|
-
setLoading(false);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async function handleSubmit() {
|
|
177
|
-
try {
|
|
178
|
-
await fetch('http://localhost:3002/api/auth/gmail/callback', {
|
|
179
|
-
method: 'POST',
|
|
180
|
-
headers: { 'Content-Type': 'application/json' },
|
|
181
|
-
body: JSON.stringify({ code })
|
|
182
|
-
});
|
|
183
|
-
onClose();
|
|
184
|
-
} catch (error) {
|
|
185
|
-
console.error(error);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return (
|
|
190
|
-
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
|
191
|
-
<div className="bg-white rounded-3xl p-8 max-w-lg w-full mx-4">
|
|
192
|
-
<h2 className="text-2xl font-bold mb-4">Connect Gmail</h2>
|
|
193
|
-
{loading ? (
|
|
194
|
-
<div className="flex items-center justify-center py-8">
|
|
195
|
-
<Loader2 className="w-8 h-8 animate-spin text-blue-600" />
|
|
196
|
-
</div>
|
|
197
|
-
) : (
|
|
198
|
-
<>
|
|
199
|
-
<p className="text-slate-600 mb-4">Open this URL to authorize:</p>
|
|
200
|
-
<a
|
|
201
|
-
href={authUrl}
|
|
202
|
-
target="_blank"
|
|
203
|
-
rel="noopener noreferrer"
|
|
204
|
-
className="block p-3 bg-blue-50 rounded-xl text-blue-600 text-sm break-all hover:bg-blue-100 transition-colors mb-4"
|
|
205
|
-
>
|
|
206
|
-
{authUrl}
|
|
207
|
-
</a>
|
|
208
|
-
<input
|
|
209
|
-
type="text"
|
|
210
|
-
placeholder="Paste authorization code here"
|
|
211
|
-
value={code}
|
|
212
|
-
onChange={(e) => setCode(e.target.value)}
|
|
213
|
-
className="w-full px-4 py-3 border rounded-xl mb-4"
|
|
214
|
-
/>
|
|
215
|
-
<div className="flex gap-3">
|
|
216
|
-
<button
|
|
217
|
-
onClick={onClose}
|
|
218
|
-
className="flex-1 py-2 border rounded-xl hover:bg-slate-50"
|
|
219
|
-
>
|
|
220
|
-
Cancel
|
|
221
|
-
</button>
|
|
222
|
-
<button
|
|
223
|
-
onClick={handleSubmit}
|
|
224
|
-
disabled={!code}
|
|
225
|
-
className="flex-1 py-2 bg-blue-600 text-white rounded-xl hover:bg-blue-700 disabled:opacity-50"
|
|
226
|
-
>
|
|
227
|
-
Submit
|
|
228
|
-
</button>
|
|
229
|
-
</div>
|
|
230
|
-
</>
|
|
231
|
-
)}
|
|
232
|
-
</div>
|
|
233
|
-
</div>
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
function M365AuthDialog({ onClose }: { onClose: () => void }) {
|
|
238
|
-
const [deviceCode, setDeviceCode] = useState('');
|
|
239
|
-
const [userCode, setUserCode] = useState('');
|
|
240
|
-
const [message, setMessage] = useState('');
|
|
241
|
-
const [loading, setLoading] = useState(true);
|
|
242
|
-
|
|
243
|
-
useEffect(() => {
|
|
244
|
-
initiateFlow();
|
|
245
|
-
}, []);
|
|
246
|
-
|
|
247
|
-
async function initiateFlow() {
|
|
248
|
-
try {
|
|
249
|
-
const res = await fetch('http://localhost:3002/api/auth/m365/device-flow', {
|
|
250
|
-
method: 'POST'
|
|
251
|
-
});
|
|
252
|
-
const data = await res.json();
|
|
253
|
-
setDeviceCode(data.device_code);
|
|
254
|
-
setUserCode(data.user_code);
|
|
255
|
-
setMessage(data.message);
|
|
256
|
-
} catch (error) {
|
|
257
|
-
console.error(error);
|
|
258
|
-
} finally {
|
|
259
|
-
setLoading(false);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async function completeFlow() {
|
|
264
|
-
try {
|
|
265
|
-
await fetch('http://localhost:3002/api/auth/m365/complete', {
|
|
266
|
-
method: 'POST',
|
|
267
|
-
headers: { 'Content-Type': 'application/json' },
|
|
268
|
-
body: JSON.stringify({ device_code: deviceCode })
|
|
269
|
-
});
|
|
270
|
-
onClose();
|
|
271
|
-
} catch (error) {
|
|
272
|
-
console.error(error);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return (
|
|
277
|
-
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
|
278
|
-
<div className="bg-white rounded-3xl p-8 max-w-lg w-full mx-4">
|
|
279
|
-
<h2 className="text-2xl font-bold mb-4">Connect Microsoft 365</h2>
|
|
280
|
-
{loading ? (
|
|
281
|
-
<div className="flex items-center justify-center py-8">
|
|
282
|
-
<Loader2 className="w-8 h-8 animate-spin text-blue-600" />
|
|
283
|
-
</div>
|
|
284
|
-
) : (
|
|
285
|
-
<>
|
|
286
|
-
<p className="text-slate-600 mb-4">{message}</p>
|
|
287
|
-
<div className="bg-blue-50 rounded-xl p-6 text-center mb-6">
|
|
288
|
-
<p className="text-sm text-slate-600 mb-2">Enter this code:</p>
|
|
289
|
-
<p className="text-4xl font-mono font-bold text-blue-600">{userCode}</p>
|
|
290
|
-
</div>
|
|
291
|
-
<div className="flex gap-3">
|
|
292
|
-
<button
|
|
293
|
-
onClick={onClose}
|
|
294
|
-
className="flex-1 py-2 border rounded-xl hover:bg-slate-50"
|
|
295
|
-
>
|
|
296
|
-
Cancel
|
|
297
|
-
</button>
|
|
298
|
-
<button
|
|
299
|
-
onClick={completeFlow}
|
|
300
|
-
className="flex-1 py-2 bg-blue-600 text-white rounded-xl hover:bg-blue-700"
|
|
301
|
-
>
|
|
302
|
-
I've Authenticated
|
|
303
|
-
</button>
|
|
304
|
-
</div>
|
|
305
|
-
</>
|
|
306
|
-
)}
|
|
307
|
-
</div>
|
|
308
|
-
</div>
|
|
309
|
-
);
|
|
310
|
-
}
|