Skip to content

Commit ca6b361

Browse files
committed
feat: Implement integration status API and enhance account management
- Added a new API endpoint to fetch the integration status for Google and Outlook. - Updated AccountManager component to display integration status and handle loading states. - Improved error handling and user feedback for missing credentials in the UI. - Refactored settings store to exclude sensitive API keys from persisted state.
1 parent 3387471 commit ca6b361

File tree

4 files changed

+102
-18
lines changed

4 files changed

+102
-18
lines changed

TODO.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# IMPORTANT
2-
- recurring tasks broken for outlook sync
2+
- pending waitlist - need a way to resend emails with new tokens or for users that signup again to get a new email
33
- synced tasks are not set to auto-schedule by default
4+
- hide upcoming tasks not working
5+
- project sidebar edit/sync not shown properly in production when project name is too long
46
- check out this comment https://www.reddit.com/r/selfhosted/comments/1irj353/comment/mjgcajo/?%24deep_link=true&correlation_id=ca91f555-ee0e-5331-bd75-473ac484ff09&ref=email_comment_reply&ref_campaign=email_comment_reply&ref_source=email&%243p=e_as&_branch_match_id=1262094978557361170&utm_medium=Email+Amazon+SES&_branch_referrer=H4sIAAAAAAAAA32O0WqEMBBFv8Z9U1djut2ClELb3wjZZKJjYxImEelLv70j9bkwgZs75zJ3LiXll7YlsBZLo1NqPIavVqTXqh9EGkHpfGEZCScM2quN%2FDgfqUq8Vf0nz77vzZk3cWWD%2BGXwbo65gOUP2yuEkll2SIuQgpXzG1qjPQSrSWFWIe4qJggqx40MMLIuk9FLPM4IviT7wQIkdTSsxHuhjaEnE4nA64IxKLTsG33vnJSyBrhCLYXo6oe9yXq4CW2G58G5651zBI5hWDV6dRZUBMl%2F%2F%2B2U0WvSOIV%2FobPqiVx%2B2AMiDJN6UNwz0PhhJ%2FgFVuHGA2YBAAA%3D
57
-
68

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { NextResponse, NextRequest } from "next/server";
2+
import { prisma } from "@/lib/prisma";
3+
import { logger } from "@/lib/logger";
4+
import { authenticateRequest } from "@/lib/auth/api-auth";
5+
6+
const LOG_SOURCE = "IntegrationStatusAPI";
7+
8+
export async function GET(request: NextRequest) {
9+
try {
10+
// Authenticate the request (any logged in user can access this)
11+
const auth = await authenticateRequest(request, LOG_SOURCE);
12+
if ("response" in auth) {
13+
return auth.response;
14+
}
15+
16+
// Get system settings
17+
const settings = await prisma.systemSettings.findFirst();
18+
19+
// Only return boolean status of whether integrations are configured
20+
return NextResponse.json({
21+
google: {
22+
configured: !!(
23+
settings?.googleClientId && settings?.googleClientSecret
24+
),
25+
},
26+
outlook: {
27+
configured: !!(
28+
settings?.outlookClientId &&
29+
settings?.outlookClientSecret &&
30+
settings?.outlookTenantId
31+
),
32+
},
33+
});
34+
} catch (error) {
35+
logger.error(
36+
"Failed to fetch integration status",
37+
{ error: error instanceof Error ? error.message : "Unknown error" },
38+
LOG_SOURCE
39+
);
40+
return NextResponse.json(
41+
{ error: "Failed to fetch integration status" },
42+
{ status: 500 }
43+
);
44+
}
45+
}

src/components/settings/AccountManager.tsx

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import { useState, useCallback } from "react";
1+
import { useState, useCallback, useEffect } from "react";
22
import { useSettingsStore } from "@/store/settings";
3-
import { useEffect } from "react";
43
import { Button } from "@/components/ui/button";
54
import {
65
Card,
@@ -14,17 +13,49 @@ import { AvailableCalendars } from "./AvailableCalendars";
1413
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
1514
import { AlertCircle } from "lucide-react";
1615
import { CalDAVAccountForm } from "./CalDAVAccountForm";
16+
import { logger } from "@/lib/logger";
17+
18+
const LOG_SOURCE = "AccountManager";
19+
20+
interface IntegrationStatus {
21+
google: { configured: boolean };
22+
outlook: { configured: boolean };
23+
}
1724

1825
export function AccountManager() {
1926
const { accounts, refreshAccounts, removeAccount } = useSettingsStore();
20-
const { system } = useSettingsStore();
2127
const [showAvailableFor, setShowAvailableFor] = useState<string | null>(null);
2228
const [showCalDAVForm, setShowCalDAVForm] = useState(false);
29+
const [integrationStatus, setIntegrationStatus] = useState<IntegrationStatus>(
30+
{
31+
google: { configured: false },
32+
outlook: { configured: false },
33+
}
34+
);
35+
const [isLoading, setIsLoading] = useState(true);
2336

2437
useEffect(() => {
2538
refreshAccounts();
2639
}, [refreshAccounts]);
2740

41+
useEffect(() => {
42+
// Fetch integration status
43+
fetch("/api/integration-status")
44+
.then((res) => res.json())
45+
.then((data) => {
46+
setIntegrationStatus(data);
47+
setIsLoading(false);
48+
})
49+
.catch((error) => {
50+
logger.error(
51+
"Failed to fetch integration status",
52+
{ error: error instanceof Error ? error.message : "Unknown error" },
53+
LOG_SOURCE
54+
);
55+
setIsLoading(false);
56+
});
57+
}, []);
58+
2859
const handleConnect = (provider: "GOOGLE" | "OUTLOOK") => {
2960
if (provider === "GOOGLE") {
3061
window.location.href = `/api/calendar/google/auth`;
@@ -47,12 +78,6 @@ export function AccountManager() {
4778
);
4879
}, []);
4980

50-
const showGoogleCredentialsWarning =
51-
!system.googleClientId || !system.googleClientSecret;
52-
53-
const showOutlookCredentialsWarning =
54-
!system.outlookClientId || !system.outlookClientSecret;
55-
5681
const handleCalDAVSuccess = () => {
5782
setShowCalDAVForm(false);
5883
refreshAccounts();
@@ -68,38 +93,38 @@ export function AccountManager() {
6893
</CardDescription>
6994
</CardHeader>
7095
<CardContent className="space-y-6">
71-
{showGoogleCredentialsWarning && (
96+
{!integrationStatus.google.configured && (
7297
<Alert variant="destructive">
7398
<AlertCircle className="h-4 w-4" />
7499
<AlertTitle>Missing Google Credentials</AlertTitle>
75100
<AlertDescription>
76-
Please go to the System Settings tab and configure your Google
77-
Client ID and Secret before connecting Google Calendar.
101+
Please contact your administrator to configure Google Calendar
102+
integration.
78103
</AlertDescription>
79104
</Alert>
80105
)}
81106

82-
{showOutlookCredentialsWarning && (
107+
{!integrationStatus.outlook.configured && (
83108
<Alert variant="destructive">
84109
<AlertCircle className="h-4 w-4" />
85110
<AlertTitle>Missing Outlook Credentials</AlertTitle>
86111
<AlertDescription>
87-
Please go to the System Settings tab and configure your Outlook
88-
Client ID and Secret before connecting Outlook Calendar.
112+
Please contact your administrator to configure Outlook Calendar
113+
integration.
89114
</AlertDescription>
90115
</Alert>
91116
)}
92117

93118
<div className="flex flex-wrap gap-2">
94119
<Button
95120
onClick={() => handleConnect("GOOGLE")}
96-
disabled={showGoogleCredentialsWarning}
121+
disabled={!integrationStatus.google.configured || isLoading}
97122
>
98123
Connect Google Calendar
99124
</Button>
100125
<Button
101126
onClick={() => handleConnect("OUTLOOK")}
102-
disabled={showOutlookCredentialsWarning}
127+
disabled={!integrationStatus.outlook.configured || isLoading}
103128
>
104129
Connect Outlook Calendar
105130
</Button>

src/store/settings.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,18 @@ export const useSettingsStore = create<SettingsStore>()(
478478
}),
479479
{
480480
name: "calendar-settings",
481+
partialize: (state) => ({
482+
...state,
483+
system: {
484+
...state.system,
485+
googleClientId: undefined,
486+
googleClientSecret: undefined,
487+
outlookClientId: undefined,
488+
outlookClientSecret: undefined,
489+
outlookTenantId: undefined,
490+
resendApiKey: undefined,
491+
},
492+
}),
481493
}
482494
)
483495
);

0 commit comments

Comments
 (0)