Skip to content

Commit 728c1b5

Browse files
authored
Merge pull request #69 from ArjinAlbay/main
The bugs in the sidebar have been resolved and a feature has been added that starts capturing data when logged into the system.
2 parents bc335b7 + 1fe6440 commit 728c1b5

File tree

10 files changed

+113
-99
lines changed

10 files changed

+113
-99
lines changed

src/app/api/auth/[...nextauth]/route.ts

Lines changed: 17 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,27 @@
11
import NextAuth from "next-auth/next"
22
import GitHubProvider from "next-auth/providers/github"
33

4+
const NEXTAUTH_SECRET = process.env.NEXTAUTH_SECRET
5+
if (process.env.NODE_ENV === 'production' && !NEXTAUTH_SECRET) {
6+
throw new Error('NEXTAUTH_SECRET is required in production.')
7+
}
8+
const GITHUB_CLIENT_ID = process.env.GITHUB_CLIENT_ID
9+
const GITHUB_CLIENT_SECRET = process.env.GITHUB_CLIENT_SECRET
10+
if (
11+
process.env.NODE_ENV === 'production' &&
12+
(!GITHUB_CLIENT_ID || !GITHUB_CLIENT_SECRET)
13+
) {
14+
throw new Error('GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET are required in production.')
15+
}
16+
417
const authOptions = {
18+
secret: NEXTAUTH_SECRET,
519
providers: [
620
GitHubProvider({
7-
clientId: process.env.GITHUB_CLIENT_ID!,
8-
clientSecret: process.env.GITHUB_CLIENT_SECRET!,
9-
authorization: {
10-
params: {
11-
scope: 'read:user user:email public_repo'
12-
}
13-
}
14-
})
21+
clientId: GITHUB_CLIENT_ID!,
22+
clientSecret: GITHUB_CLIENT_SECRET!,
23+
}),
1524
],
16-
callbacks: {
17-
async jwt({ token, account, profile }: {
18-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
19-
token: any;
20-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
21-
account: any;
22-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
23-
profile?: any
24-
}) {
25-
if (account?.access_token) {
26-
token.accessToken = account.access_token
27-
token.login = profile?.login
28-
}
29-
return token
30-
},
31-
async session({ session, token }: {
32-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
33-
session: any;
34-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
35-
token: any
36-
}) {
37-
if (token.accessToken) {
38-
session.accessToken = token.accessToken
39-
}
40-
if (token.login && session.user) {
41-
session.user.login = token.login
42-
}
43-
return session
44-
},
45-
async redirect({ url, baseUrl }: {
46-
url: string;
47-
baseUrl: string
48-
}) {
49-
if (url.startsWith('/')) return `${baseUrl}${url}`
50-
if (new URL(url).origin === baseUrl) return url
51-
return `${baseUrl}/auth/callback`
52-
}
53-
},
5425
pages: {
5526
signIn: '/login',
5627
error: '/login'
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { githubAPIClient } from '@/lib/api/github-api-client'
3+
4+
export async function GET(
5+
request: NextRequest,
6+
{ params }: { params: Promise<{ username: string }> }
7+
) {
8+
try {
9+
// Next.js 15'te params bir Promise döndürüyor
10+
const { username } = await params
11+
12+
if (!username) {
13+
return NextResponse.json(
14+
{ error: 'Username parameter is required' },
15+
{ status: 400 }
16+
)
17+
}
18+
19+
const userAnalytics = await githubAPIClient.getUserAnalytics(username)
20+
21+
if (!userAnalytics) {
22+
return NextResponse.json(
23+
{ error: 'User not found or data could not be retrieved' },
24+
{ status: 404 }
25+
)
26+
}
27+
28+
return NextResponse.json({
29+
username,
30+
data: userAnalytics,
31+
timestamp: new Date().toISOString()
32+
})
33+
} catch (error) {
34+
console.error('User API error:', error)
35+
36+
if (error instanceof Error && error.message.includes('not found')) {
37+
return NextResponse.json(
38+
{ error: 'User not found' },
39+
{ status: 404 }
40+
)
41+
}
42+
43+
return NextResponse.json(
44+
{ error: 'Internal server error' },
45+
{ status: 500 }
46+
)
47+
}
48+
}

src/app/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { OAuthSessionSync } from '@/components/providers/OAuthSessionSync'
77

88
import { HydrationBoundary } from "@/components/providers/HydrationBoundary";
99
import { NotificationProvider } from "@/components/common/NotificationProvider";
10+
import { DataInitializer } from "@/components/providers/DataInitializer";
1011

1112

1213
const geistSans = Geist({
@@ -39,6 +40,7 @@ export default function RootLayout({
3940
<ThemeProvider defaultTheme="system" storageKey="githubmon-theme">
4041
<HydrationBoundary>
4142
<OAuthSessionSync />
43+
<DataInitializer />
4244
{children}
4345
<NotificationProvider />
4446
</HydrationBoundary>

src/app/quick-wins/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
} from 'lucide-react'
1515
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
1616
import { useState, useEffect } from 'react'
17+
import { RateLimitWarning } from '@/components/common/RateLimitWarning'
1718

1819
const VALID_TABS = ['good-issues', 'easy-fixes'] as const
1920
type ValidTab = typeof VALID_TABS[number]

src/app/search/page.tsx

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,17 @@ export default function SearchPage() {
115115
try {
116116
const analytics = await githubAPIClient.getUserAnalytics(userParam);
117117
if (analytics) {
118-
// Convert GitHubUserDetailed to the expected profile format
119118
const convertedAnalytics: UserAnalytics = {
120119
profile: analytics.profile ? {
121120
avatar_url: analytics.profile.avatar_url,
122121
login: analytics.profile.login,
123122
type: analytics.profile.type,
124-
bio: analytics.profile.bio,
123+
bio: analytics.profile.bio ?? null,
125124
public_repos: analytics.profile.public_repos,
126125
followers: analytics.profile.followers,
127126
following: analytics.profile.following,
128-
location: analytics.profile.location,
129-
company: analytics.profile.company,
127+
location: analytics.profile.location ?? null,
128+
company: analytics.profile.company ?? null,
130129
html_url: analytics.profile.html_url
131130
} : undefined,
132131
overview: analytics.overview,
@@ -174,7 +173,6 @@ export default function SearchPage() {
174173
[]
175174
);
176175

177-
// Scroll spy effect - ONLY h2 titles matter
178176
useEffect(() => {
179177
const handleScroll = throttle(() => {
180178
const sectionIds = ['overview', 'behavior', 'star', 'code', 'code-review', 'issue', 'monthly-stats', 'contribution-activities'];
@@ -216,33 +214,10 @@ export default function SearchPage() {
216214
return () => window.removeEventListener("scroll", handleScroll);
217215
}, [activeSection, throttle]);
218216

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-
240217
useEffect(() => {
241218
if (userParam || repoParam) {
242219
const query = userParam || repoParam || "";
243220
const type = userParam ? "users" : "repos";
244-
245-
// Clear previous state when switching users
246221
setUserAnalytics(null);
247222
setSearchResults({
248223
repos: [],
@@ -256,7 +231,6 @@ export default function SearchPage() {
256231
performSearch(query, type);
257232
setHasSearched(true);
258233

259-
// If searching for a user, load analytics
260234
if (userParam) {
261235
loadUserAnalytics();
262236
}

src/app/settings/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Input } from '@/components/ui/input'
88
import { usePreferencesStore } from '@/stores'
99
import { useRequireAuth } from '@/hooks/useAuth'
1010
import { ThemeSelector } from '@/components/theme/ThemeToggle'
11-
import { GitHubTokenSetup } from '@/components/common/GitHubTokenSetup'
11+
// import { GitHubTokenSetup } from '@/components/common/GitHubTokenSetup'
1212
import { cookieUtils } from '@/lib/cookies'
1313

1414
export default function SettingsPage() {
@@ -48,7 +48,7 @@ export default function SettingsPage() {
4848
{/* GitHub API Token Setup */}
4949
<section>
5050
<h3 className="text-lg font-medium mb-4">🔑 GitHub API Token</h3>
51-
<GitHubTokenSetup />
51+
{/* <GitHubTokenSetup /> */}
5252
</section>
5353

5454
<Card>

src/components/layout/Sidebar.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import Link from 'next/link'
44
import { useSearchParams, usePathname } from 'next/navigation'
5-
import { useState } from 'react'
5+
import { useState, useEffect } from 'react'
66
import { Button } from '@/components/ui/button'
77
import { useSidebarState, useAuthStore, useStoreHydration, useActionItemsStore } from '@/stores'
88
import { useQuickWinsStore } from '@/stores/quickWins'
@@ -22,8 +22,16 @@ export function Sidebar() {
2222

2323
const { goodIssues, easyFixes, loading: quickWinsLoading } = useQuickWinsStore()
2424

25-
const [actionRequiredOpen, setActionRequiredOpen] = useState(true)
26-
const [quickWinsOpen, setQuickWinsOpen] = useState(true)
25+
const [actionRequiredOpen, setActionRequiredOpen] = useState(false)
26+
const [quickWinsOpen, setQuickWinsOpen] = useState(false)
27+
28+
// Close accordions when navigating to dashboard
29+
useEffect(() => {
30+
if (pathname === '/dashboard') {
31+
setActionRequiredOpen(false)
32+
setQuickWinsOpen(false)
33+
}
34+
}, [pathname])
2735

2836
const currentTab = searchParams?.get('tab') || 'assigned'
2937

@@ -207,9 +215,9 @@ export function Sidebar() {
207215
{/* Quick Wins sub-items */}
208216
<CollapsibleContent className="pl-8 space-y-1 mt-1">
209217
<Link
210-
href="/quick-wins?tab=good-first-issues"
218+
href="/quick-wins?tab=good-issues"
211219
className={`flex items-center gap-2 px-3 py-1.5 text-sm rounded transition-colors
212-
${(pathname === '/quick-wins' && currentTab === 'good-first-issues')
220+
${(pathname === '/quick-wins' && currentTab === 'good-issues')
213221
? 'bg-blue-50 text-blue-600 dark:bg-blue-900/20 dark:text-blue-400'
214222
: 'text-gray-600 hover:text-blue-600 hover:bg-gray-50 dark:hover:bg-gray-800'
215223
}`}>
@@ -221,7 +229,7 @@ export function Sidebar() {
221229
{getBadgeContent('goodFirstIssues')}
222230
</Badge>
223231
</Link>
224-
<Link
232+
<Link
225233
href="/quick-wins?tab=easy-fixes"
226234
className={`flex items-center gap-2 px-3 py-1.5 text-sm rounded transition-colors
227235
${(pathname === '/quick-wins' && currentTab === 'easy-fixes')
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use client'
2+
3+
import { useEffect , useRef} from 'react'
4+
import { useAuthStore, useActionItemsStore } from '@/stores'
5+
import { useQuickWinsStore } from '@/stores/quickWins'
6+
7+
export function DataInitializer() {
8+
const { isConnected, orgData, isTokenValid } = useAuthStore()
9+
const { refreshData } = useActionItemsStore()
10+
const { fetchGoodIssues, fetchEasyFixes } = useQuickWinsStore()
11+
12+
const initializedRef = useRef(false)
13+
const tokenValid = isTokenValid()
14+
useEffect(() => {
15+
if (!initializedRef.current && isConnected && orgData && tokenValid) {
16+
initializedRef.current = true
17+
refreshData()
18+
fetchGoodIssues()
19+
fetchEasyFixes()
20+
}
21+
}, [isConnected, orgData, tokenValid, refreshData, fetchGoodIssues, fetchEasyFixes])
22+
23+
return null
24+
}

src/components/quick-wins/hooks/useQuickWins.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
import { useEffect, useCallback, useRef } from 'react'
2+
import { useEffect } from 'react'
33
import { useQuickWinsStore } from '@/stores/quickWins'
44
import { useDataCacheStore } from '@/stores/cache'
55
import { useActionItemsStore } from '@/stores'
@@ -36,21 +36,8 @@ export function useQuickWins() {
3636
const { isQuickWinsCacheExpired } = useDataCacheStore()
3737
const { setGoodFirstIssues, setEasyFixes } = useActionItemsStore()
3838

39-
const isInitialized = useRef(false)
4039

41-
const initializeData = useCallback(async () => {
42-
if (isInitialized.current) return
43-
loadFromCache()
44-
const { goodIssues: gi, easyFixes: ef } = useQuickWinsStore.getState()
45-
const needsFetch = isQuickWinsCacheExpired() || (gi.length === 0 && ef.length === 0)
46-
if (needsFetch) {
47-
await Promise.all([
48-
fetchGoodIssues(false),
49-
fetchEasyFixes(false)
50-
])
51-
}
52-
isInitialized.current = true
53-
}, [loadFromCache, isQuickWinsCacheExpired, fetchGoodIssues, fetchEasyFixes])
40+
5441

5542
useEffect(() => {
5643
if (goodIssues.length > 0) {

src/lib/api/github-api-client.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,6 @@ class GitHubAPIClient {
436436
try {
437437
const oneMonthAgo = new Date()
438438
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1)
439-
const dateString = oneMonthAgo.toISOString().split('T')[0]
440439

441440
const repoEndpoint = `/search/repositories?q=stars:>${minStars}&sort=stars&order=desc&per_page=50`
442441
const repoResponse = await this.fetchWithCache<GitHubSearchResponse<GitHubRepositoryResponse>>(repoEndpoint, true)

0 commit comments

Comments
 (0)