diff --git a/src/modules/rewards/components/BonusActivitiesItem.tsx b/src/modules/rewards/components/BonusActivitiesItem.tsx index 25c2600999..3c77b88a99 100644 --- a/src/modules/rewards/components/BonusActivitiesItem.tsx +++ b/src/modules/rewards/components/BonusActivitiesItem.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; // hooks -import { Activity, useGetRewardsActivity } from 'queries'; +import { Activity, StakeActivityResponse, UsersActivity } from 'queries'; import { useAccount } from 'hooks'; // components @@ -17,6 +17,9 @@ export type BonusActivitiesItemProps = { isLoadingItem: boolean; setErrorMessage: (errorMessage: string) => void; isLocked: boolean; + allUsersActivity: StakeActivityResponse; + isAllActivitiesLoading: boolean; + refetchActivity: () => void; }; const BonusActivitiesItem: FC = ({ @@ -25,12 +28,12 @@ const BonusActivitiesItem: FC = ({ isLoadingItem, setErrorMessage, isLocked, + allUsersActivity, + isAllActivitiesLoading, + refetchActivity, }) => { - const { - data: usersSingleActivity, - isLoading, - refetch: refetchActivity, - } = useGetRewardsActivity({ userId, activityId: activity.id }, { enabled: !!userId }); + const usersSingleActivity = allUsersActivity?.[activity?.activityType] as UsersActivity; + const isLoading = isAllActivitiesLoading; const { isWalletConnected } = useAccount(); diff --git a/src/modules/rewards/components/BonusActivitiesSection.tsx b/src/modules/rewards/components/BonusActivitiesSection.tsx index bcd6252117..2f078e50f7 100644 --- a/src/modules/rewards/components/BonusActivitiesSection.tsx +++ b/src/modules/rewards/components/BonusActivitiesSection.tsx @@ -5,7 +5,12 @@ import { FC, useState } from 'react'; import { css } from 'styled-components'; // hooks -import { useGetRewardsActivities, useGetUserRewardsDetails } from 'queries'; +import { + StakeActivityResponse, + useGetRewardsActivities, + useGetRewardsActivity, + useGetUserRewardsDetails, +} from 'queries'; import { useAccount } from 'hooks'; import { useRewardsContext } from 'contexts/RewardsContext'; @@ -41,6 +46,23 @@ const BonusActivities: FC = () => { const { isLocked } = useRewardsContext(); + // Combine all activities into a single array + const allActivities = [...bonusActivities]; + + // Extract the `activityType` from each activity and filter out any undefined values + const activityTypes = allActivities + .map((activity) => activity.activityType) // Extract `activityType` + .filter(Boolean); // Remove undefined/null values + + const { + data: allUsersActivity, + isLoading: isAllActivitiesLoading, + refetch: refetchActivity, + } = useGetRewardsActivity( + { userId: userDetails?.userId as string, activityTypes: activityTypes }, + { enabled: !!userDetails?.userId && activityTypes.length > 0 } + ); + return ( = () => { isLoadingItem={isLoading} setErrorMessage={setErrorMessage} isLocked={isLocked} + allUsersActivity={allUsersActivity as StakeActivityResponse} + isAllActivitiesLoading={isAllActivitiesLoading} + refetchActivity={refetchActivity} /> ))} diff --git a/src/modules/rewards/components/DailyRewardsSection.tsx b/src/modules/rewards/components/DailyRewardsSection.tsx index e577aeb1fe..d5c1b8f9b5 100644 --- a/src/modules/rewards/components/DailyRewardsSection.tsx +++ b/src/modules/rewards/components/DailyRewardsSection.tsx @@ -19,14 +19,19 @@ export type DailyRewardsSectionProps = {}; const DailyRewardsSection: FC = () => { const [errorMessage, setErrorMessage] = useState(''); - const { activeItem, activeDay, isActivityDisabled, isLoading, userDetails, dailyRewardsActivities, handleCheckIn } = - useDailyRewards(); + const { + activeItem, + activeDay, + isActivityDisabled, + isLoading, + userDetails, + dailyRewardsActivities, + refetchSendActivities, + } = useDailyRewards(); const { isLocked } = useRewardsContext(); - const isDailyRewardClaimed = useMemo(() => { - return isActivityDisabled && activeDay > 1 && userDetails; - }, [isActivityDisabled, activeDay, userDetails]); + const isDailyRewardClaimed = isActivityDisabled && activeDay > 1 && userDetails; const displayDailyRewards = useMemo(() => { return !isActivityDisabled && activeDay > 0 && activeItem && userDetails; @@ -85,7 +90,7 @@ const DailyRewardsSection: FC = () => { activityType={activeItem?.activityType as ActvityType} userId={userDetails?.userId as string} activityTypeId={activeItem?.id as string} - refetchActivity={() => handleCheckIn()} + refetchActivity={() => refetchSendActivities()} setErrorMessage={setErrorMessage} isLoadingActivity={false} label="Check In" diff --git a/src/modules/rewards/components/RewardsActivitiesList.tsx b/src/modules/rewards/components/RewardsActivitiesList.tsx index 6db3ba3716..eb41493cf3 100644 --- a/src/modules/rewards/components/RewardsActivitiesList.tsx +++ b/src/modules/rewards/components/RewardsActivitiesList.tsx @@ -5,7 +5,13 @@ import { css } from 'styled-components'; import { Box, Lock, Text } from 'blocks'; import { useAccount } from 'hooks'; import { walletToCAIP10 } from 'helpers/w2w'; -import { Activity, useGetRewardsActivities, useGetUserRewardsDetails } from 'queries'; +import { + Activity, + StakeActivityResponse, + useGetRewardsActivities, + useGetRewardsActivity, + useGetUserRewardsDetails, +} from 'queries'; import { useRewardsContext } from 'contexts/RewardsContext'; import { RewardsActivitiesListItem } from './RewardsActivitiesListItem'; @@ -43,6 +49,23 @@ const RewardsActivitiesList: FC = () => { const { isLocked } = useRewardsContext(); + // Combine all activities into a single array + const allActivities = [...socialActivities, ...platformRewardActivities, ...channelSubscriptionActivities]; + + // Extract the `activityType` from each activity and filter out any undefined values + const activityTypes = allActivities + .map((activity) => activity.activityType) // Extract `activityType` + .filter(Boolean); // Remove undefined/null values + + const { + data: allUsersActivity, + isLoading: isAllActivitiesLoading, + refetch: refetchActivity, + } = useGetRewardsActivity( + { userId: userDetails?.userId as string, activityTypes: activityTypes }, + { enabled: !!userDetails?.userId && activityTypes.length > 0 } + ); + return ( = () => { activity={activity} isLoadingItem={isLoading} isLocked={isLocked} + allUsersActivity={allUsersActivity as StakeActivityResponse} + isAllActivitiesLoading={isAllActivitiesLoading} + refetchActivity={refetchActivity} /> ))} {(isLocked || !isWalletConnected) && ( @@ -103,6 +129,9 @@ const RewardsActivitiesList: FC = () => { activity={activity} isLoadingItem={isLoading} isLocked={isLocked} + allUsersActivity={allUsersActivity as StakeActivityResponse} + isAllActivitiesLoading={isAllActivitiesLoading} + refetchActivity={refetchActivity} /> ))} @@ -114,6 +143,9 @@ const RewardsActivitiesList: FC = () => { activity={activity} isLoadingItem={isLoading} isLocked={isLocked} + allUsersActivity={allUsersActivity as StakeActivityResponse} + isAllActivitiesLoading={isAllActivitiesLoading} + refetchActivity={refetchActivity} /> ))} diff --git a/src/modules/rewards/components/RewardsActivitiesListItem.tsx b/src/modules/rewards/components/RewardsActivitiesListItem.tsx index e9ce84ab3a..3dac6e3ac7 100644 --- a/src/modules/rewards/components/RewardsActivitiesListItem.tsx +++ b/src/modules/rewards/components/RewardsActivitiesListItem.tsx @@ -1,6 +1,6 @@ import { FC, useEffect, useMemo, useState } from 'react'; -import { Activity, useGetRewardsActivity } from 'queries'; +import { Activity, StakeActivityResponse, UsersActivity } from 'queries'; import { useAccount } from 'hooks'; import { @@ -27,6 +27,9 @@ export type RewardActivitiesListItemProps = { activity: Activity; isLoadingItem: boolean; isLocked: boolean; + allUsersActivity: StakeActivityResponse; + isAllActivitiesLoading: boolean; + refetchActivity: () => void; }; const getUpdatedExpiryTime = (timestamp: number) => { @@ -46,13 +49,13 @@ const RewardsActivitiesListItem: FC = ({ activity, isLoadingItem, isLocked, + allUsersActivity, + isAllActivitiesLoading, + refetchActivity, }) => { const { isWalletConnected } = useAccount(); - const { - data: usersSingleActivity, - isLoading, - refetch: refetchActivity, - } = useGetRewardsActivity({ userId, activityId: activity.id }, { enabled: !!userId }); + const usersSingleActivity = allUsersActivity?.[activity?.activityType] as UsersActivity; + const isLoading = isAllActivitiesLoading; const [errorMessage, setErrorMessage] = useState(''); const { getLockStatus } = useLockedStatus(); @@ -73,7 +76,7 @@ const RewardsActivitiesListItem: FC = ({ if (activity.activityType == 'follow_push_on_discord' || activity.activityType == 'follow_push_on_twitter') { getLockStatus(); } - }, [usersSingleActivity?.status, activity.activityType]); + }, [usersSingleActivity, activity.activityType]); return ( diff --git a/src/modules/rewards/components/StakePushActivitiesListItem.tsx b/src/modules/rewards/components/StakePushActivitiesListItem.tsx index ad3ccda965..5e5e5d7e2c 100644 --- a/src/modules/rewards/components/StakePushActivitiesListItem.tsx +++ b/src/modules/rewards/components/StakePushActivitiesListItem.tsx @@ -2,7 +2,7 @@ import { FC } from 'react'; // hooks -import { Activity, useGetRewardsActivity } from 'queries'; +import { Activity, StakeActivityResponse, UsersActivity } from 'queries'; import { useAccount } from 'hooks'; // components @@ -17,6 +17,9 @@ export type StakeActivitiesItemProps = { setErrorMessage: (errorMessage: string) => void; isLocked: boolean; hasEpochEnded?: boolean; + allUsersActivity: StakeActivityResponse; + isAllActivitiesLoading: boolean; + refetchActivity: () => void; }; const StakePushActivitiesListItem: FC = ({ userId, @@ -25,15 +28,15 @@ const StakePushActivitiesListItem: FC = ({ setErrorMessage, isLocked, hasEpochEnded, + allUsersActivity, + isAllActivitiesLoading, + refetchActivity, }) => { - const { - data: usersSingleActivity, - isLoading, - refetch: refetchActivity, - } = useGetRewardsActivity({ userId, activityId: activity.id }, { enabled: !!userId }); - const { isWalletConnected } = useAccount(); + const usersSingleActivity = allUsersActivity?.[activity?.activityType] as UsersActivity; + const isLoading = isAllActivitiesLoading; + const hasActivityEndedUnclaimed = usersSingleActivity?.status !== 'COMPLETED' && hasEpochEnded; const isLockedOrNotConnected = isLocked || !isWalletConnected; diff --git a/src/modules/rewards/components/StakePushSection.tsx b/src/modules/rewards/components/StakePushSection.tsx index d7c4692c9b..3647943ae1 100644 --- a/src/modules/rewards/components/StakePushSection.tsx +++ b/src/modules/rewards/components/StakePushSection.tsx @@ -3,7 +3,7 @@ import { FC, useMemo, useState } from 'react'; // hooks import { useAccount } from 'hooks'; -import { useGetUserRewardsDetails } from 'queries'; +import { StakeActivityResponse, useGetRewardsActivity, useGetUserRewardsDetails } from 'queries'; import { useRewardsContext } from 'contexts/RewardsContext'; // helpers @@ -46,6 +46,23 @@ const StakePushSection: FC = ({ title, subtitle, timeline, mult return daysToReset != null && activityResetDate >= 0 && activityResetDate <= 7 && !multiplier && isWalletConnected; }, [daysToReset, activityResetDate, multiplier, isWalletConnected]); + // Combine all activities into a single array + const allActivities = [...uniV2PushArray, ...stakePushArray]; + + // Extract the `activityType` from each activity and filter out any undefined values + const activityTypes = allActivities + .map((activity) => activity.activityType) // Extract `activityType` + .filter(Boolean); // Remove undefined/null values + + const { + data: allUsersActivity, + isLoading: isAllActivitiesLoading, + refetch: refetchActivity, + } = useGetRewardsActivity( + { userId: userDetails?.userId as string, activityTypes: activityTypes }, + { enabled: !!userDetails?.userId && activityTypes.length > 0 } + ); + return ( = ({ title, subtitle, timeline, mult setErrorMessage={setErrorMessage} isLocked={isLocked} hasEpochEnded={hasEpochEnded} + allUsersActivity={allUsersActivity as StakeActivityResponse} + isAllActivitiesLoading={isAllActivitiesLoading} + refetchActivity={refetchActivity} /> ))} @@ -184,6 +204,9 @@ const StakePushSection: FC = ({ title, subtitle, timeline, mult setErrorMessage={setErrorMessage} isLocked={isLocked} hasEpochEnded={hasEpochEnded} + allUsersActivity={allUsersActivity as StakeActivityResponse} + isAllActivitiesLoading={isAllActivitiesLoading} + refetchActivity={refetchActivity} /> ))} diff --git a/src/modules/rewards/hooks/useDailyRewards.tsx b/src/modules/rewards/hooks/useDailyRewards.tsx index 80350e3a17..366642bdd1 100644 --- a/src/modules/rewards/hooks/useDailyRewards.tsx +++ b/src/modules/rewards/hooks/useDailyRewards.tsx @@ -54,7 +54,7 @@ const useDailyRewards = () => { // Check if dailyRewardsActivities is available and all activityTitles are defined const areActivitiesDefined = dailyRewardsActivities && activityTitles?.every((title) => title !== undefined); - const { data: sendRecentActivities } = useGetRewardActivityStatus( + const { data: sendRecentActivities, refetch: refetchSendActivities } = useGetRewardActivityStatus( { userId: userDetails?.userId as string, activities: activityTitles as string[], @@ -71,7 +71,7 @@ const useDailyRewards = () => { }, []); // Handle success response from sending recent activities - const handleCheckIn = () => { + const handleCheckIn = useCallback(() => { if (!sendRecentActivities || Object.keys(sendRecentActivities).length === 0) return; setIsLoadingRewards(true); @@ -99,7 +99,7 @@ const useDailyRewards = () => { setActiveDay(newDay); setActiveItem(newDayData); setIsLoadingRewards(false); - }; + }, [sendRecentActivities]); // Effect for handling check-in when user details change or wallet is connected useEffect(() => { @@ -122,6 +122,7 @@ const useDailyRewards = () => { userDetails, dailyRewardsActivities, handleCheckIn, + refetchSendActivities, resetState, }; }; diff --git a/src/queries/hooks/rewards/useGetRewardsActivity.ts b/src/queries/hooks/rewards/useGetRewardsActivity.ts index 29d2800a0c..8a40c5dc92 100644 --- a/src/queries/hooks/rewards/useGetRewardsActivity.ts +++ b/src/queries/hooks/rewards/useGetRewardsActivity.ts @@ -1,14 +1,14 @@ import { UseQueryOptions, useQuery } from '@tanstack/react-query'; import { rewardsActivity } from '../../queryKeys'; import { getRewardsActivity } from '../../services/rewards'; -import { UsersActivity } from '../../types'; +import { StakeActivityResponse } from '../../types'; export const useGetRewardsActivity = ( - { userId, activityId }: { userId: string; activityId: string }, - config?: Partial> + { userId, activityTypes }: { userId: string; activityTypes: string[] }, + config?: Partial> ) => - useQuery({ - queryKey: [rewardsActivity, userId, activityId], - queryFn: () => getRewardsActivity(userId, activityId), - ...config + useQuery({ + queryKey: [rewardsActivity, userId, activityTypes], + queryFn: () => getRewardsActivity(userId, activityTypes), + ...config, }); diff --git a/src/queries/models/rewards/getRewardsActivityModelCreator.ts b/src/queries/models/rewards/getRewardsActivityModelCreator.ts index 70b7483a6e..8acafe9a1c 100644 --- a/src/queries/models/rewards/getRewardsActivityModelCreator.ts +++ b/src/queries/models/rewards/getRewardsActivityModelCreator.ts @@ -1,3 +1,3 @@ -import { UsersActivity } from 'queries/types'; +import { StakeActivityResponse } from 'queries/types'; -export const getRewardsActivityModelCreator = (response: UsersActivity): UsersActivity => response; +export const getRewardsActivityModelCreator = (response: StakeActivityResponse): StakeActivityResponse => response; diff --git a/src/queries/services/rewards/getRewardsActivity.ts b/src/queries/services/rewards/getRewardsActivity.ts index 62e3f8834a..8662432918 100644 --- a/src/queries/services/rewards/getRewardsActivity.ts +++ b/src/queries/services/rewards/getRewardsActivity.ts @@ -2,9 +2,13 @@ import axios from 'axios'; import { getRewardsBaseURL } from 'queries/baseURL'; import { getRewardsActivityModelCreator } from 'queries/models'; -export const getRewardsActivity = (userId: string, activityId: string) => - axios({ +export const getRewardsActivity = (userId: string, activityTypes: string[]) => { + // Join the activities array into a string + const activitiesString = activityTypes.join(','); + + return axios({ method: 'GET', - url: `${getRewardsBaseURL()}/users/${userId}/activity/${activityId}`, + url: `${getRewardsBaseURL()}/users/${userId}/activities/bytype?types=${activitiesString}`, }).then((response) => getRewardsActivityModelCreator(response.data)); +}; diff --git a/src/queries/types/rewards.ts b/src/queries/types/rewards.ts index bb9ec7b4c4..085ced02f2 100644 --- a/src/queries/types/rewards.ts +++ b/src/queries/types/rewards.ts @@ -97,6 +97,15 @@ export type UsersActivity = { updatedAt: string; // ISO 8601 date string }; +export type UsersActivityError = { + error: string; +}; + +// The key can be any string, and the value can be either StakeActivitySuccess or StakeActivityError +export type StakeActivityResponse = { + [key: string]: UsersActivity | UsersActivityError; +}; + type Prop = { [key: string]: string; };