diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b929d015..6e61208b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: 构建编译 +name: Build Application on: workflow_dispatch: diff --git a/src/apis/frontiter.api.ts b/src/apis/frontiter.api.ts index a4b014b5..134b4c17 100644 --- a/src/apis/frontiter.api.ts +++ b/src/apis/frontiter.api.ts @@ -1,5 +1,6 @@ import { AxiosInstance } from 'axios' import request, { PaginationResponse, TPagination } from './request' +import { data } from 'react-router-dom' interface Response { data: T @@ -15,6 +16,23 @@ export interface TaskRewardInfo { reward_value: number } +export type ActiveStatus = 'ACTIVE' | 'INACTIVE' | 'COMPLETED' +export interface FrontierActivityInfoItem { + activity_id: string + start_time: string + end_time: string + reward_mode: 'EQUAL_SPLIT_ON_END' | 'FIRST_COME_FIRST_SERVE' + min_ranking_grade: string + days_left: number + total_asset_amount: number + max_reward_count: number + reward_asset_type: string + participants: number + submissions: number + status: ActiveStatus + rules?: readonly string[] +} + export interface TaskDetail { frontier_id: string task_id: string @@ -31,6 +49,7 @@ export interface TaskDetail { question_status?: number // 1: available, 2: no more questions, 3. need to change question group data_requirements: unknown reward_info: readonly TaskRewardInfo[] + status: 'PENDING' | 'SUBMITTED' | 'REFUSED' | 'ADOPT' txHashUrl: string } @@ -45,6 +64,13 @@ export interface FrontierListItem { reputation_permission: number status: string title: string + activities: FrontierActivityInfoItem[] + // start + // total_asset_amount: number + // reward_asset_type: string + // min_ranking_grade: string + // days_left: number + // end template_ext?: { template_id: string gif_resource?: string @@ -157,7 +183,15 @@ class frontier { } async getFrontiers(): Promise> { - const res = await this.request.post('/v2/frontier/list ') + const res = await this.request.post('/v2/frontier/list ', data) + return res.data + } + + async getFrontierActivityInfo(data: { + frontier_id: string + status?: ActiveStatus + }): Promise> { + const res = await this.request.post('/v2/frontier/activity/info', data) return res.data } diff --git a/src/assets/home/badge.svg b/src/assets/home/badge.svg new file mode 100644 index 00000000..5435e5ed --- /dev/null +++ b/src/assets/home/badge.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/home/dollar-circle.svg b/src/assets/home/dollar-circle.svg new file mode 100644 index 00000000..afe7f5fc --- /dev/null +++ b/src/assets/home/dollar-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/home/hourglass.svg b/src/assets/home/hourglass.svg new file mode 100644 index 00000000..21922142 --- /dev/null +++ b/src/assets/home/hourglass.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/home/activity-info.tsx b/src/components/home/activity-info.tsx new file mode 100644 index 00000000..043ab9d6 --- /dev/null +++ b/src/components/home/activity-info.tsx @@ -0,0 +1,139 @@ +import { cn } from '@udecode/cn' +import { useParams } from 'react-router-dom' +import { useEffect, useState } from 'react' +import dayjs from 'dayjs' + +import { ChevronUp } from 'lucide-react' + +import { formatNumber } from '@/utils/str' +import frontierApi, { FrontierActivityInfoItem } from '@/apis/frontiter.api' + +export default function ActivityInfo({ className }: { className?: string }) { + const { frontier_id } = useParams() + const [activityInfoList, setActivityInfoList] = useState([]) + + async function getFrontierActivityInfo(frontier_id: string) { + const res = await frontierApi.getFrontierActivityInfo({ frontier_id }) + if (res.errorCode === 0) { + setActivityInfoList(res.data) + console.log(res.data) + } + } + useEffect(() => { + if (!frontier_id) return + getFrontierActivityInfo(frontier_id) + }, [frontier_id]) + + return ( +
0 ? 'block' : 'hidden', className)}> +
    + {activityInfoList.map((item) => ( +
  • +
    +
    +
    Duration
    +
    + {dayjs(item.start_time).format('YYYY-MM-DD')} to {dayjs(item.end_time).format('YYYY-MM-DD')} +
    +
    +
    +
    Min Quality
    +
    + {item.min_ranking_grade} +
    +
    +
    +
    Total Rewards
    +
    + {formatNumber(item.total_asset_amount || 0)} + {item.reward_asset_type} +
    +
    + {item.reward_mode === 'EQUAL_SPLIT_ON_END' ? ( +
    +
    Total Submissions
    +
    {formatNumber(item.submissions || 0)}
    +
    + ) : ( +
    +
    Target
    +
    + + + + + + + + + + + + + {formatNumber(item.submissions || 0)}/{formatNumber(item.max_reward_count || 0)} +
    +
    + )} +
    + +
  • + ))} +
+
+ ) +} + +function getRulesText(activity: FrontierActivityInfoItem) { + return [ + 'Multiple valid submissions count for reward sharing', + `Minimum data quality requirement: Grade ${activity.min_ranking_grade}`, + 'Below standard submissions receive points reward', + 'Quality assessment based on accuracy and completeness', + activity.reward_mode === 'FIRST_COME_FIRST_SERVE' + ? 'First come, first served: Fixed rewards for reaching baseline score during activity period. Once required quantity is reached, no more rewards will be distributed even if activity continues.Below standard gets points reward' + : 'Divide and share mode: Multiple submissions valid, each counts for sharing. Below standard gets points reward.' + ] +} + +function Rules({ activity }: { activity: FrontierActivityInfoItem }) { + const rules = getRulesText(activity) + const [showRules, setShowRules] = useState(false) + + return ( +
+

+ 📋 Activity Rules{' '} + setShowRules(!showRules)} + /> +

+
    + {rules?.map((rule) =>
  • {rule}
  • )} +
+
+ ) +} diff --git a/src/components/home/frontiers.tsx b/src/components/home/frontiers.tsx index 8aecbb3c..7a2aad1a 100644 --- a/src/components/home/frontiers.tsx +++ b/src/components/home/frontiers.tsx @@ -1,9 +1,14 @@ -import arrowRight from '@/assets/icons/arrow-right.svg' +import { message, Spin } from 'antd' import { useNavigate } from 'react-router-dom' import { useEffect, useMemo, useState } from 'react' + +import arrowRight from '@/assets/icons/arrow-right.svg?url' +import badgeIcon from '@/assets/home/badge.svg#file' +import DollarCircle from '@/assets/home/dollar-circle.svg?react' +import Hourglass from '@/assets/home/hourglass.svg?react' + import { FrontierListItem } from '@/apis/frontiter.api' import { frontierStoreActions, useFrontierStore } from '@/stores/frontier.store' -import { message, Spin } from 'antd' const Frontiers = () => { const navigate = useNavigate() @@ -12,11 +17,20 @@ const Frontiers = () => { const { frontierList } = useFrontierStore() const displayFrontiers = useMemo(() => { - return frontierList.filter((item) => { - return !['FOOD_TPL_000002', 'FOOD_TPL_000003', 'FOOD_TPL_000004', 'FOOD_TPL_000005'].includes( - item.template_ext?.template_id || '' - ) - }) + return frontierList + .filter((item) => { + return !['FOOD_TPL_000002', 'FOOD_TPL_000003', 'FOOD_TPL_000004', 'FOOD_TPL_000005'].includes( + item.template_ext?.template_id || '' + ) + }) + .map((item) => { + return { + ...item, + activities: item.activities?.filter((activity) => { + return activity.status === 'ACTIVE' + }) + } + }) }, [frontierList]) async function getFrontiers() { @@ -54,7 +68,7 @@ const Frontiers = () => { {displayFrontiers.map((item) => (
handleFrontierClick(item)} > { className="size-full object-cover transition-all group-hover:scale-[1.2]" />
+ {item.activities?.[0] && ( +
+ {item.activities?.[0].min_ranking_grade || 'S'} +
+ )}
-

{item.title}

-
{item.description.frontier_desc}
-
-
- Start - +

{item.title}

+
+
+
+ {item.activities?.[0] ? ( +
+
+ + {item.activities?.[0].total_asset_amount || 0} + {item.activities?.[0].reward_asset_type} +
+
+ + {item.activities?.[0].days_left || 0}D +
+
+ ) : ( +
{item.description.frontier_desc}
+ )} +
+ Start + +
+
+
diff --git a/src/router.tsx b/src/router.tsx index 0f745c8b..b0d0aa0d 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -3,7 +3,6 @@ import { lazy, useEffect } from 'react' // layouts import FrontierLayout from '@/layouts/frontier-layout' -// import SettingsLayout from '@/layouts/settings-layout' import UserInfoLayout from '@/layouts/userinfo-layout' import AppLayout from '@/layouts/app-layout' import ArenaLayout from '@/layouts/arena-layout' @@ -22,13 +21,6 @@ const NewJourney = lazy(() => import('@/views/new-journey')) const ActivityGroup = lazy(() => import('@/views/quest/activity-group')) const Activity = lazy(() => import('@/views/quest/activity')) -// settings -// const SettingAccount = lazy(() => import('@/views/settings/account')) -// const SettingReward = lazy(() => import('@/views/settings/reward')) -// const SettingReputation = lazy(() => import('@/views/settings/reputation')) -// const SettingUserNFT = lazy(() => import('@/views/settings/user-nft')) -// const SettingUserSBT = lazy(() => import('@/views/settings/user-sbt')) - // user info const UserInfo = lazy(() => import('@/views/userinfo/index')) const UserInfoReward = lazy(() => import('@/views/userinfo/reward')) @@ -122,13 +114,6 @@ export default function Router() { }> } /> - {/* }> - } /> - } /> - } /> - } /> */} - {/* } /> */} - {/* */} }> } /> } /> diff --git a/src/stores/frontier.store.ts b/src/stores/frontier.store.ts index 33321e1e..491cbbd9 100644 --- a/src/stores/frontier.store.ts +++ b/src/stores/frontier.store.ts @@ -1,10 +1,18 @@ -import frontierApi, { FrontierListItem, TaskDetail, SubmissionStatics, SubmissionRecord } from '@/apis/frontiter.api' +import frontierApi, { + FrontierListItem, + TaskDetail, + SubmissionStatics, + SubmissionRecord, + FrontierActivityInfoItem, + ActiveStatus +} from '@/apis/frontiter.api' import { debounce } from 'lodash' import { proxy, useSnapshot } from 'valtio' import { message } from 'antd' type FrontierStore = { frontierList: FrontierListItem[] + frontierActivities: FrontierActivityInfoItem[] pageData: { list: TaskDetail[] total: number @@ -31,6 +39,7 @@ type FrontierStore = { export const frontiersStore = proxy({ frontierList: [], + frontierActivities: [], pageData: { list: [], total: 0, @@ -134,6 +143,15 @@ async function getFrontierList() { return res.data } +async function getFrontierActivities(data: { frontier_id: string; status?: ActiveStatus }) { + const res = await frontierApi.getFrontierActivityInfo({ + frontier_id: data.frontier_id, + status: data.status + }) + frontiersStore.frontierActivities = res.data || [] + return res.data +} + export function useFrontierStore() { return useSnapshot(frontiersStore) } @@ -166,6 +184,7 @@ export const getFrontierUserRecords = debounce(async (params: { page: number }) export const frontierStoreActions = { getFrontierList, + getFrontierActivities, changeFrontiersFilter, changeFrontiersHistoryFilter, getFrontierUserStatics, diff --git a/src/views/frontiers/home.tsx b/src/views/frontiers/home.tsx index 3edd5a39..efd167b5 100644 --- a/src/views/frontiers/home.tsx +++ b/src/views/frontiers/home.tsx @@ -4,6 +4,8 @@ import { ArrowLeft } from 'lucide-react' import { useNavigate, useParams } from 'react-router-dom' import FrontierTaskList from '@/components/robotics/task-list' +import ActivityInfo from '@/components/home/activity-info' + import { useEffect, useState } from 'react' import frontierApi, { FrontierItemType, MediaName } from '@/apis/frontiter.api' import XIcon from '@/assets/robotics/x-logo.svg' @@ -68,6 +70,7 @@ export default function Component() {
{frontierInfo?.description}
+
diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 6a8856de..a516d9c6 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -10,4 +10,9 @@ interface Window { declare module '*.md' { const value: string export default value -} \ No newline at end of file +} + +declare module '*#file' { + const src: string + export default src +}