diff --git a/packages/backend/src/app.module.ts b/packages/backend/src/app.module.ts index 6e424a4d..daa47962 100644 --- a/packages/backend/src/app.module.ts +++ b/packages/backend/src/app.module.ts @@ -16,9 +16,11 @@ import { AuthModule } from './auth/auth.module'; import { PriceModule } from './price/price.module'; import { FeatureRequestModule } from './feature-request/feature-request.module'; import { AdminModule } from './admin/admin.module'; -import { PartnerModule } from './partner/partner.module'; -import { QuestModule } from './quest/quest.module'; -import { RewardModule } from './reward/reward.module'; +// Hidden: Partner account-report endpoint disabled per ops request. +// import { PartnerModule } from './partner/partner.module'; +// Hidden: Quest + Leaderboard + Reward/Claim flows disabled (FE already hidden in #245). +// import { QuestModule } from './quest/quest.module'; +// import { RewardModule } from './reward/reward.module'; import { BalanceAlertModule } from './balance-alert/balance-alert.module'; import { ScheduleModule } from '@nestjs/schedule'; import { X402Module } from './x402/x402.module'; @@ -45,9 +47,9 @@ const featureX402 = process.env.FEATURE_X402_DEPOSIT === 'true'; PriceModule, FeatureRequestModule, AdminModule, - PartnerModule, - QuestModule, - RewardModule, + // PartnerModule, + // QuestModule, + // RewardModule, BalanceAlertModule, ScheduleModule.forRoot(), ...(featureX402 ? [X402Module] : []), diff --git a/packages/backend/src/transaction/transaction-executor.service.ts b/packages/backend/src/transaction/transaction-executor.service.ts index cbd55c06..70a6187d 100644 --- a/packages/backend/src/transaction/transaction-executor.service.ts +++ b/packages/backend/src/transaction/transaction-executor.service.ts @@ -34,7 +34,8 @@ import { import { EventsService } from '@/events/events.service'; import { Transaction } from '@/generated/prisma/client'; import { AnalyticsLoggerService } from '@/common/analytics-logger.service'; -import { QuestService } from '@/quest/quest.service'; +// Quest disabled — see app.module.ts. +// import { QuestService } from '@/quest/quest.service'; @Injectable() export class TransactionExecutorService { @@ -46,7 +47,7 @@ export class TransactionExecutorService { private readonly relayerService: RelayerService, private readonly eventsService: EventsService, private readonly analyticsLogger: AnalyticsLoggerService, - private readonly questService: QuestService, + // private readonly questService: QuestService, ) {} /** @@ -106,7 +107,7 @@ export class TransactionExecutorService { ); // 3. Mark as executed only on success - const { pointsAwarded } = await this.markExecuted(txId, txHash); + await this.markExecuted(txId, txHash); this.analyticsLogger.logExecute( userAddress, @@ -114,7 +115,7 @@ export class TransactionExecutorService { txHash, ); - return { txId, txHash, status: TxStatus.EXECUTED, pointsAwarded }; + return { txId, txHash, status: TxStatus.EXECUTED }; } catch (error) { this.logger.error(`Execute failed for txId ${txId}: ${error.message}`); @@ -265,27 +266,6 @@ export class TransactionExecutorService { }, }); - // Award quest points (only for TRANSFER and BATCH transactions) - let pointsAwarded = 0; - if ( - transaction.type === TxType.TRANSFER || - transaction.type === TxType.BATCH - ) { - try { - const successfulTxPoints = await this.questService.awardSuccessfulTx( - txId, - transaction.createdBy, - ); - const firstTxPoints = await this.questService.awardAccountFirstTx( - transaction.accountAddress, - txId, - ); - pointsAwarded = successfulTxPoints + firstTxPoints; - } catch (error) { - this.logger.error(`Failed to award quest points: ${error.message}`); - } - } - // Emit event for status update const eventData: TxStatusEventData = { txId, @@ -298,8 +278,7 @@ export class TransactionExecutorService { eventData, ); - const result = await updatedTx; - return { ...result, pointsAwarded }; + return updatedTx; }); } diff --git a/packages/backend/src/transaction/transaction.module.ts b/packages/backend/src/transaction/transaction.module.ts index aeb64ac3..e1a52714 100644 --- a/packages/backend/src/transaction/transaction.module.ts +++ b/packages/backend/src/transaction/transaction.module.ts @@ -9,7 +9,8 @@ import { RelayerModule } from '@/relayer-wallet/relayer-wallet.module'; import { BatchItemModule } from '@/batch-item/batch-item.module'; import { EventsModule } from '@/events/events.module'; import { AnalyticsLoggerService } from '@/common/analytics-logger.service'; -import { QuestModule } from '@/quest/quest.module'; +// Quest disabled — see app.module.ts. +// import { QuestModule } from '@/quest/quest.module'; @Module({ imports: [ @@ -18,7 +19,7 @@ import { QuestModule } from '@/quest/quest.module'; RelayerModule, BatchItemModule, EventsModule, - QuestModule, + // QuestModule, ], controllers: [TransactionController], providers: [ diff --git a/packages/nextjs/app/leaderboard/page.tsx b/packages/nextjs/app/leaderboard/page.tsx index c396b132..e128b866 100644 --- a/packages/nextjs/app/leaderboard/page.tsx +++ b/packages/nextjs/app/leaderboard/page.tsx @@ -1,158 +1,6 @@ -"use client"; +// Leaderboard is hidden — see #245. Original page kept in git history (commit 894eeac) for restore. +import { redirect } from "next/navigation"; -import { useState } from "react"; -import Image from "next/image"; -import { formatCampaignStartDate, getAvailableWeeks, getCurrentWeek, getLastCompletedWeek } from "@polypay/shared"; -import type { LeaderboardFilter } from "@polypay/shared"; -import { NextPage } from "next"; -import { SectionAvatar } from "~~/components/leader-board"; -import { ClaimSection } from "~~/components/leader-board/ClaimSection"; -import { LeaderBoardTable } from "~~/components/leader-board/LeaderBoardTable"; -import { QuestFloatingButton } from "~~/components/quest/QuestFloatingButton"; -import { useModalApp } from "~~/hooks"; -import { useClaimSummary } from "~~/hooks/api/useClaim"; - -const WEEKS = [1, 2]; - -const LeaderBoardPage: NextPage = () => { - const [filter, setFilter] = useState("weekly"); - const [selectedWeek, setSelectedWeek] = useState(() => { - const lastCompleted = getLastCompletedWeek(); - const available = getAvailableWeeks(); - return lastCompleted || available[0] || 1; - }); - const { openModal } = useModalApp(); - - // Get campaign state - const currentWeek = getCurrentWeek(); - const availableWeeks = getAvailableWeeks(); - const lastCompletedWeek = getLastCompletedWeek(); - const campaignNotStarted = currentWeek === 0; - - // Fetch claim summary to check if user has claimed - const { data: claimSummary } = useClaimSummary(); - - // Check if selected week has reward (claimed or not) - const selectedWeekData = claimSummary?.weeks.find(w => w.week === selectedWeek); - - // Get week param only when filter is weekly - const weekParam = filter === "weekly" ? selectedWeek : undefined; - - const handleClaim = () => { - if (!claimSummary) return; - openModal("claimReward", { week: selectedWeek }); - }; - - return ( -
- {/* Header */} -
-
-

- Leaderboard -

- - {/* Filter Tabs */} -
- - -
-
- - {/* Week Buttons - Only show when filter is "weekly" */} - {filter === "weekly" && ( -
- {/* Week buttons */} -
- {WEEKS.map(week => { - const isAvailable = availableWeeks.includes(week); - const isSelected = selectedWeek === week; - - // Check if this week has unclaimed reward (for pink dot) - const weekData = claimSummary?.weeks.find(w => w.week === week); - const isCompleted = lastCompletedWeek !== null && week <= lastCompletedWeek; - const showPinkDot = isCompleted && weekData && !weekData.isClaimed && weekData.rewardZen > 0; - - return ( - - ); - })} -
-
- )} - - {/* Claim Section - Only show when filter is "weekly" */} - {filter === "weekly" && ( - - )} -
- - {/* Content */} -
- {campaignNotStarted ? ( -
- Campaign not started -
- Campaign has not started yet - Please check back on {formatCampaignStartDate()} -
-
- ) : ( - <> - - - - )} -
- - -
- ); -}; - -export default LeaderBoardPage; +export default function LeaderboardPage() { + redirect("/dashboard"); +} diff --git a/packages/nextjs/app/quest/page.tsx b/packages/nextjs/app/quest/page.tsx index 5490298e..ab3f9408 100644 --- a/packages/nextjs/app/quest/page.tsx +++ b/packages/nextjs/app/quest/page.tsx @@ -1,114 +1,6 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { QuestCategory, QuestCode } from "@polypay/shared"; -import QuestIntroModal from "~~/components/modals/QuestIntroModal"; -import { ComingSoon, QuestCard, QuestSection } from "~~/components/quest"; -import { QuestFloatingButton } from "~~/components/quest/QuestFloatingButton"; -import { useMyAccounts, useQuests } from "~~/hooks/api"; -import { useAppRouter } from "~~/hooks/app/useRouteApp"; -import { useIdentityStore } from "~~/services/store"; -import { useQuestIntroStore } from "~~/services/store/questIntroStore"; -import { notification } from "~~/utils/scaffold-eth"; +// Quest is hidden — see #245. Original page kept in git history (commit 894eeac) for restore. +import { redirect } from "next/navigation"; export default function QuestPage() { - const { data: quests, isLoading } = useQuests(); - const { hasSeenIntro, _hasHydrated } = useQuestIntroStore(); - const [showIntroModal, setShowIntroModal] = useState(false); - - const { commitment } = useIdentityStore(); - const { data: accounts = [] } = useMyAccounts(); - const router = useAppRouter(); - - const featuredQuests = quests?.filter(q => q.type === QuestCategory.RECURRING) ?? []; - const dailyQuests = quests?.filter(q => q.type === QuestCategory.DAILY) ?? []; - - // Show intro modal on first visit - useEffect(() => { - if (_hasHydrated && !hasSeenIntro) { - setShowIntroModal(true); - } - }, [_hasHydrated, hasSeenIntro]); - - const handleQuestClick = (code: string) => { - if (!commitment) { - notification.info("Please sign in to continue"); - return; - } - - if (accounts.length === 0) { - notification.info("Please create an account first"); - router.goToDashboardNewAccount(); - return; - } - - switch (code) { - case QuestCode.ACCOUNT_FIRST_TX: - router.goToDashboardNewAccount(); - break; - case QuestCode.SUCCESSFUL_TX: - router.goToTransfer(); - break; - default: - break; - } - }; - - if (isLoading) { - return ( -
-
-
- ); - } - - return ( -
- {/* Page title */} -

- All Quests -

- - {/* Featured Quests */} - -
- {featuredQuests.length > 0 ? ( - featuredQuests.map(quest => ( - handleQuestClick(quest.code)} - /> - )) - ) : ( -

No featured quests available

- )} -
-
- - {/* Daily Quests */} - - {dailyQuests.length > 0 ? ( -
- {dailyQuests.map(quest => ( - handleQuestClick(quest.code)} - /> - ))} -
- ) : ( - - )} -
- - setShowIntroModal(false)} /> - -
- ); + redirect("/dashboard"); } diff --git a/packages/nextjs/components/modals/ModalLayout.tsx b/packages/nextjs/components/modals/ModalLayout.tsx index ae2f4434..b756cfa2 100644 --- a/packages/nextjs/components/modals/ModalLayout.tsx +++ b/packages/nextjs/components/modals/ModalLayout.tsx @@ -52,8 +52,9 @@ const modals: ModalRegistry = { }), switchAccount: dynamic(() => import("./SwitchAccountModal"), { ssr: false }), disclaimer: dynamic(() => import("./DisclaimerModal"), { ssr: false }), - claimReward: dynamic(() => import("./ClaimRewardModal"), { ssr: false }), - questIntro: dynamic(() => import("./QuestIntroModal"), { ssr: false }), + // Quest + Leaderboard hidden — modals orphaned. + // claimReward: dynamic(() => import("./ClaimRewardModal"), { ssr: false }), + // questIntro: dynamic(() => import("./QuestIntroModal"), { ssr: false }), createBatchFromContacts: dynamic(() => import("./CreateBatchFromContactsModal"), { ssr: false }), depositX402: dynamic(() => import("./DepositModal"), { ssr: false }), receiveMethod: dynamic(() => import("./ReceiveMethodModal"), { ssr: false }), diff --git a/packages/nextjs/components/quest/QuestFloatingButton.tsx b/packages/nextjs/components/quest/QuestFloatingButton.tsx index 3af93bb3..1c883448 100644 --- a/packages/nextjs/components/quest/QuestFloatingButton.tsx +++ b/packages/nextjs/components/quest/QuestFloatingButton.tsx @@ -1,15 +1,16 @@ "use client"; import Image from "next/image"; -import { useModalApp } from "~~/hooks"; + +// import { useModalApp } from "~~/hooks"; export const QuestFloatingButton = () => { - const { openModal } = useModalApp(); + // const { openModal } = useModalApp(); return ( <>