Skip to content

Commit bc335b7

Browse files
authored
Merge pull request #67 from MuslimeKaya/main
refactor: enhance GitHub API client with commit data handling and improve caching strategy
2 parents 7887564 + 48d47d3 commit bc335b7

File tree

15 files changed

+540
-394
lines changed

15 files changed

+540
-394
lines changed

eslint.config.mjs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ const compat = new FlatCompat({
1111

1212
const eslintConfig = [
1313
...compat.extends("next/core-web-vitals", "next/typescript"),
14+
{
15+
rules: {
16+
// Allow unused variables in catch clauses (common for error handling)
17+
"@typescript-eslint/no-unused-vars": [
18+
"error",
19+
{
20+
"argsIgnorePattern": "^_",
21+
"varsIgnorePattern": "^_",
22+
"caughtErrors": "none"
23+
}
24+
],
25+
// Allow unescaped quotes in JSX (common in descriptions)
26+
"react/no-unescaped-entities": "off"
27+
}
28+
}
1429
];
1530

1631
export default eslintConfig;

src/app/action-required/page.tsx

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,34 +41,41 @@ export default function ActionRequiredPage() {
4141
const VALID_TABS = ['assigned', 'mentions', 'stale'] as const
4242
type ValidTab = typeof VALID_TABS[number]
4343

44-
const tabParam = searchParams.get('tab')
44+
const tabParam = searchParams?.get('tab')
4545
const currentTab: ValidTab = VALID_TABS.includes(tabParam as ValidTab)
4646
? (tabParam as ValidTab)
4747
: 'assigned'
4848

4949
useEffect(() => {
50-
refreshData().catch((error) => {
51-
console.error('Failed to refresh action required data:', error)
50+
refreshData().catch(() => {
51+
// Silent error handling for refresh data
5252
})
5353
}, [refreshData])
5454

55-
const getActionItems = (type: string) => {
55+
// Helper function to get action items by type
56+
const getActionItems = (type: 'assigned' | 'mentions' | 'stale') => {
5657
switch (type) {
57-
case 'assigned': return assignedItems
58-
case 'mentions': return mentionItems
59-
case 'stale': return staleItems
60-
default: return []
58+
case 'assigned':
59+
return assignedItems
60+
case 'mentions':
61+
return mentionItems
62+
case 'stale':
63+
return staleItems
64+
default:
65+
return []
6166
}
6267
}
6368

64-
const isValidUrl = (url: string) => {
69+
// Helper function to validate URLs
70+
const isValidUrl = (url?: string): boolean => {
71+
if (!url) return false
6572
try {
66-
const parsed = new URL(url);
67-
return parsed.protocol === 'https:' && parsed.hostname.includes('github.com');
73+
const parsed = new URL(url)
74+
return parsed.protocol === 'https:' && parsed.hostname.includes('github.com')
6875
} catch {
69-
return false;
76+
return false
7077
}
71-
};
78+
}
7279

7380
const handleTabChange = (tab: string) => {
7481
if (VALID_TABS.includes(tab as ValidTab)) {
@@ -92,7 +99,7 @@ export default function ActionRequiredPage() {
9299
return (
93100
<Layout>
94101
<div className="max-w-7xl mx-auto p-6 space-y-6">
95-
<PageHeader />
102+
<PageHeader />
96103

97104
{/* Hero Section */}
98105
<div className="mb-8">
@@ -108,13 +115,13 @@ export default function ActionRequiredPage() {
108115
</div>
109116

110117
{/* Action Required Tabs */}
111-
<Tabs
112-
value={currentTab}
118+
<Tabs
119+
value={currentTab}
113120
onValueChange={(value) => {
114121
if (VALID_TABS.includes(value as ValidTab)) {
115122
handleTabChange(value)
116123
}
117-
}}
124+
}}
118125
className="w-full"
119126
>
120127
<TabsList className="grid w-full grid-cols-3">
@@ -327,7 +334,7 @@ export default function ActionRequiredPage() {
327334
</TabsContent>
328335
</Tabs>
329336
</div>
330-
337+
331338
<SearchModal />
332339
</Layout>
333340
)

src/app/api/auth/logout/route.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { NextResponse } from 'next/server'
1+
import { NextResponse } from 'next/server'
22

33
export async function POST() {
44
try {
@@ -24,8 +24,7 @@ export async function POST() {
2424
})
2525

2626
return response
27-
} catch (error) {
28-
console.error('Logout error:', error)
27+
} catch {
2928
return NextResponse.json(
3029
{ error: 'Logout failed' },
3130
{ status: 500 }

src/app/auth/callback/page.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ interface ExtendedSession {
1818

1919
export default function AuthCallback() {
2020
const { data: session, status } = useSession()
21-
const router = useRouter()
21+
const router = useRouter()
2222
const { setOrgData, setConnected, setTokenExpiry } = useAuthStore()
2323

24-
useEffect(() => {
24+
useEffect(() => {
2525
const extendedSession = session as ExtendedSession
2626
if (status === 'authenticated' && extendedSession?.accessToken && extendedSession.user) {
2727
try {
@@ -35,8 +35,7 @@ useEffect(() => {
3535
setTokenExpiry(expiryDate.toISOString())
3636
setConnected(true)
3737
router.replace('/dashboard')
38-
} catch (error) {
39-
console.error('Failed to set auth data:', error)
38+
} catch {
4039
router.replace('/')
4140
}
4241
} else if (status === 'unauthenticated') {

src/app/quick-wins/page.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export default function QuickWinsPage() {
2626
const [currentTab, setCurrentTab] = useState<ValidTab>('good-issues')
2727

2828
useEffect(() => {
29-
const tabParam = searchParams.get('tab')
29+
const tabParam = searchParams?.get('tab')
3030
if (tabParam && VALID_TABS.includes(tabParam as ValidTab)) {
3131
setCurrentTab(tabParam as ValidTab)
3232
}
@@ -39,9 +39,7 @@ export default function QuickWinsPage() {
3939
goodIssuesError,
4040
easyFixesError,
4141
refreshGoodIssues,
42-
refreshEasyFixes,
43-
44-
42+
refreshEasyFixes
4543
} = useQuickWins()
4644

4745
const handleTabChange = (tab: string) => {
@@ -50,7 +48,6 @@ export default function QuickWinsPage() {
5048
router.push(`/quick-wins?tab=${tab}`)
5149
}
5250
}
53-
5451

5552
if (isLoading) {
5653
return (
@@ -68,8 +65,13 @@ export default function QuickWinsPage() {
6865
return (
6966
<Layout>
7067
<div className="max-w-7xl mx-auto p-6 space-y-6">
71-
<PageHeader />
72-
68+
69+
<PageHeader />
70+
71+
{/* Rate Limit Warning */}
72+
<RateLimitWarning />
73+
74+
7375
{/* Hero Section */}
7476
<div className="mb-8">
7577
<div className="flex items-center justify-between mb-2">
@@ -85,7 +87,6 @@ export default function QuickWinsPage() {
8587
</p>
8688
</div>
8789

88-
8990
{/* Quick Wins Tabs */}
9091
<Tabs
9192
value={currentTab}
@@ -116,7 +117,7 @@ export default function QuickWinsPage() {
116117
error={goodIssuesError}
117118
onRefresh={refreshGoodIssues}
118119
title="Good First Issues"
119-
120+
120121
emptyMessage="No good first issues found"
121122
/>
122123
</TabsContent>
@@ -133,10 +134,8 @@ export default function QuickWinsPage() {
133134
</TabsContent>
134135
</Tabs>
135136

136-
137137
</div>
138138

139-
140139
</Layout >
141140
)
142141
}

src/app/search/page.tsx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ interface UserAnalytics {
6464
avatar_url: string;
6565
login: string;
6666
type: string;
67-
bio?: string;
67+
bio: string | null;
6868
public_repos: number;
6969
followers: number;
7070
following: number;
71-
location?: string;
72-
company?: string;
71+
location: string | null;
72+
company: string | null;
7373
html_url: string;
7474
};
7575
overview?: Array<UserOverviewData>;
@@ -216,6 +216,27 @@ export default function SearchPage() {
216216
return () => window.removeEventListener("scroll", handleScroll);
217217
}, [activeSection, throttle]);
218218

219+
const loadUserAnalytics = useCallback(async () => {
220+
if (!userParam) return;
221+
const requestedUser = userParam;
222+
223+
setLoadingAnalytics(true);
224+
try {
225+
const analytics = await githubAPIClient.getUserAnalytics(requestedUser);
226+
// Ignore if param changed while awaiting
227+
if (requestedUser !== userParam) return;
228+
setUserAnalytics(analytics);
229+
} catch {
230+
// Fallback to null if API fails
231+
if (requestedUser !== userParam) return;
232+
setUserAnalytics(null);
233+
} finally {
234+
if (requestedUser === userParam) {
235+
setLoadingAnalytics(false);
236+
}
237+
}
238+
}, [userParam]);
239+
219240
useEffect(() => {
220241
if (userParam || repoParam) {
221242
const query = userParam || repoParam || "";
@@ -267,7 +288,6 @@ export default function SearchPage() {
267288
});
268289
}
269290
} catch (error) {
270-
console.error("Search error:", error);
271291
setSearchResults({
272292
repos: [],
273293
users: [],

src/app/settings/page.tsx

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
'use client'
22

3-
import { useState} from 'react'
3+
import { useState } from 'react'
44
import { Layout } from '@/components/layout/Layout'
55
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
66
import { Button } from '@/components/ui/button'
77
import { Input } from '@/components/ui/input'
8-
import { usePreferencesStore } from '@/stores'
8+
import { usePreferencesStore } from '@/stores'
99
import { useRequireAuth } from '@/hooks/useAuth'
1010
import { ThemeSelector } from '@/components/theme/ThemeToggle'
11+
import { GitHubTokenSetup } from '@/components/common/GitHubTokenSetup'
1112
import { cookieUtils } from '@/lib/cookies'
1213

1314
export default function SettingsPage() {
14-
const { isLoading, orgData } = useRequireAuth()
15+
const { isLoading, orgData } = useRequireAuth()
1516
const { resetPreferences } = usePreferencesStore()
1617
const [tempOrgName, setTempOrgName] = useState(orgData?.orgName || '')
17-
const [tempToken, setTempToken] = useState('')
1818

1919
const handleClearData = () => {
2020
if (confirm('Tüm veriler silinecek. Emin misiniz?')) {
@@ -25,8 +25,6 @@ export default function SettingsPage() {
2525
}
2626
}
2727

28-
29-
3028
if (isLoading) {
3129
return (
3230
<Layout>
@@ -42,10 +40,17 @@ export default function SettingsPage() {
4240

4341
return (
4442
<Layout>
45-
<div className="max-w-2xl">
46-
<h2 className="text-xl font-semibold mb-4">Ayarlar</h2>
43+
<div className="max-w-4xl mx-auto">
44+
<h2 className="text-xl font-semibold mb-6">Ayarlar</h2>
45+
46+
<div className="space-y-8">
47+
48+
{/* GitHub API Token Setup */}
49+
<section>
50+
<h3 className="text-lg font-medium mb-4">🔑 GitHub API Token</h3>
51+
<GitHubTokenSetup />
52+
</section>
4753

48-
<div className="space-y-6">
4954
<Card>
5055
<CardHeader>
5156
<CardTitle>GitHub Bağlantısı</CardTitle>
@@ -60,19 +65,6 @@ export default function SettingsPage() {
6065
/>
6166
</div>
6267

63-
<div>
64-
<label className="block text-sm font-medium mb-2">API Token (Opsiyonel)</label>
65-
<Input
66-
type="password"
67-
value={tempToken}
68-
onChange={(e) => setTempToken(e.target.value)}
69-
placeholder="Mevcut token'ı değiştirmek için girin"
70-
/>
71-
<p className="text-xs text-gray-500 mt-1">
72-
Token olmadan da çalışır, ancak rate limit düşük olur.
73-
</p>
74-
</div>
75-
7668
<Button>
7769
Kaydet
7870
</Button>

src/components/charts/AreaChart.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,23 @@ export default function AreaChart({
2626
stack = false,
2727
...chartProps
2828
}: AreaChartProps) {
29+
// Handle empty data
30+
if (!data || data.length === 0) {
31+
const option: EChartsOption = {
32+
title: {
33+
text: 'No Data Available',
34+
left: 'center',
35+
top: 'middle',
36+
textStyle: {
37+
fontSize: 16,
38+
fontWeight: 'normal',
39+
color: '#9ca3af'
40+
}
41+
}
42+
};
43+
return <EChartsBase option={option} {...chartProps} />;
44+
}
45+
2946
const option: EChartsOption = {
3047
title: title ? {
3148
text: title,

0 commit comments

Comments
 (0)