From 25a9fa90b5591bd51850aae08bdf78a7178f5be3 Mon Sep 17 00:00:00 2001 From: Amateur <2863217986@qq.com> Date: Thu, 18 Jul 2024 17:25:42 +0800 Subject: [PATCH] feat: issue completion leaderboard --- src/components/forms/user-auth-form.tsx | 33 --------- .../issue-completion-leaderboard.tsx | 74 +++++++++++++++++++ src/components/leaderboard-row.tsx | 26 +++++++ src/components/recent-sales.tsx | 63 ---------------- src/pages/dashboard/index.tsx | 20 +---- src/service/index.ts | 16 ++++ 6 files changed, 119 insertions(+), 113 deletions(-) create mode 100644 src/components/issue-completion-leaderboard.tsx create mode 100644 src/components/leaderboard-row.tsx delete mode 100644 src/components/recent-sales.tsx diff --git a/src/components/forms/user-auth-form.tsx b/src/components/forms/user-auth-form.tsx index 4642561..b4c715c 100644 --- a/src/components/forms/user-auth-form.tsx +++ b/src/components/forms/user-auth-form.tsx @@ -1,21 +1,12 @@ import { Button } from '@/components/ui/button' -import { zodResolver } from '@hookform/resolvers/zod' // import { signIn } from 'next-auth/react' // import { useSearchParams } from 'next/navigation' -import { useLocation } from 'react-router-dom' -import { useState } from 'react' -import { useForm } from 'react-hook-form' -import * as z from 'zod' import { Icons } from '@/components/icons' // import GithubSignInButton from '../github-auth-button' const CLIENT_ID = 'Ov23li86Nz0RcXbj54Z5' const REDIRECT_URI = 'http://localhost:3000/auth/github/callback' -const signIn = (...args: unknown[]) => { - location.href = '/' -} - const githubOAuth = () => { window.location.href = `http://github.com/login/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=user:email` } @@ -32,31 +23,7 @@ const GithubSignInButton = () => { ) } -const formSchema = z.object({ - email: z.string().email({ message: 'Enter a valid email address' }), -}) - -type UserFormValue = z.infer - export default function UserAuthForm() { - const searchParams = new URLSearchParams(useLocation().search) - const callbackUrl = searchParams.get('callbackUrl') - const [loading, setLoading] = useState(false) - const defaultValues = { - email: 'demo@gmail.com', - } - const form = useForm({ - resolver: zodResolver(formSchema), - defaultValues, - }) - - const onSubmit = async (data: UserFormValue) => { - signIn('credentials', { - email: data.email, - callbackUrl: callbackUrl ?? '/dashboard', - }) - } - return ( <>
diff --git a/src/components/issue-completion-leaderboard.tsx b/src/components/issue-completion-leaderboard.tsx new file mode 100644 index 0000000..4a158d6 --- /dev/null +++ b/src/components/issue-completion-leaderboard.tsx @@ -0,0 +1,74 @@ +import api from '@/service' +import { Issue } from '@/types' +import { useEffect, useState } from 'react' +import LeaderboardRow from './leaderboard-row' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +export function IssueCompletionLeaderboard() { + const [issues, setIssues] = useState([]) + const [assigneeStats, setAssigneeStats] = useState<{ + [key: string]: { avatarSrc: string; name: string; html: string; completedTasks: number } + }>({}) + const [openedCount, setOpenedCount] = useState(0) + const [closedCount, setClosedCount] = useState(0) + + useEffect(() => { + api.fetchIssues('YoubetDao', 'youbet-test-repo').then((data) => { + if (data) { + setIssues(data) + + const stats: { [key: string]: { avatarSrc: string; name: string; html: string; completedTasks: number } } = {} + let opened = 0 + let closed = 0 + + data.forEach((issue) => { + issue.assignees.forEach((assignee) => { + if (!stats[assignee.login]) { + stats[assignee.login] = { + avatarSrc: assignee.avatar_url, + name: assignee.login, + html: assignee.html_url, // 将 email 改为 html 字段 + completedTasks: 0, + } + } + if (issue.state === 'closed') { + stats[assignee.login].completedTasks += 1 + } + }) + if (issue.state === 'closed') { + closed++ + } else { + opened++ + } + }) + + setAssigneeStats(stats) + setOpenedCount(opened) + setClosedCount(closed) + } + }) + }, []) + + return ( + + + Issue Completion Leaderboard + + Opened: {openedCount} Closed: {closedCount} + + + +
+ {Object.values(assigneeStats).map((assignee, index) => ( + + ))} +
+
+
+ ) +} diff --git a/src/components/leaderboard-row.tsx b/src/components/leaderboard-row.tsx new file mode 100644 index 0000000..7a16419 --- /dev/null +++ b/src/components/leaderboard-row.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' +interface LeaderboardRowProps { + avatarSrc: string + name: string + html: string + completedTasks: number +} + +const LeaderboardRow: React.FC = ({ avatarSrc, name, html, completedTasks }) => { + return ( +
+ + + {name.charAt(0)} + +
+

{name}

+

{html}

+
+
{completedTasks}
+
+ ) +} + +export default LeaderboardRow diff --git a/src/components/recent-sales.tsx b/src/components/recent-sales.tsx deleted file mode 100644 index b6c85dd..0000000 --- a/src/components/recent-sales.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar' - -export function RecentSales() { - return ( -
-
- - - OM - -
-

Olivia Martin

-

olivia.martin@email.com

-
-
+$1,999.00
-
-
- - - JL - -
-

Jackson Lee

-

jackson.lee@email.com

-
-
+$39.00
-
-
- - - IN - -
-

Isabella Nguyen

-

isabella.nguyen@email.com

-
-
+$299.00
-
-
- - - WK - -
-

William Kim

-

will@email.com

-
-
+$99.00
-
-
- - - SD - -
-

Sofia Davis

-

sofia.davis@email.com

-
-
+$39.00
-
-
- ) -} diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx index fa4b36c..9c096dd 100644 --- a/src/pages/dashboard/index.tsx +++ b/src/pages/dashboard/index.tsx @@ -1,12 +1,10 @@ -import { Button } from '@/components/ui/button' -import { CalendarDateRangePicker } from '@/components/date-range-picker' -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card' +import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { ScrollArea } from '@/components/ui/scroll-area' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { AreaGraph } from '@/components/charts/AreaGraph' import { BarGraph } from '@/components/charts/BarGraph' import { PieGraph } from '@/components/charts/PieGraph' -import { RecentSales } from '@/components/recent-sales' +import { IssueCompletionLeaderboard } from '@/components/issue-completion-leaderboard' export default function Dashboard() { return ( @@ -15,10 +13,6 @@ export default function Dashboard() {

Hi, Welcome back 👋

-
- - -
@@ -121,15 +115,7 @@ export default function Dashboard() {
- - - Recent Sales - You made 265 sales this month. - - - - - +
diff --git a/src/service/index.ts b/src/service/index.ts index d8e8c69..f8422fd 100644 --- a/src/service/index.ts +++ b/src/service/index.ts @@ -1,5 +1,6 @@ import Cookies from 'js-cookie' import http from './instance' +import { Issue } from '@/types' const api = { fetchUserInfo: async (code: string) => { @@ -19,6 +20,21 @@ const api = { console.error('Error fetching user info:', error) } }, + fetchIssues: async (org: string, project: string): Promise => { + try { + const response = await http.get('/tasks', { + params: { org, project }, + }) + + if (response.data) { + return response.data + } + return null + } catch (error) { + console.error('Error fetching user info:', error) + return null + } + }, } export default api