Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wallet] ui: fix recorded streak #599

Merged
merged 3 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 43 additions & 8 deletions apps/wallet/src/features/Loyalty/ActionCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { useSnapshot } from 'utils/hooks';

import PointTag from '../components/PointTag';
import {
checkIfUserCanDoAction,
extractDataFromMetadata,
getActionLogo,
getCycleEndTime,
Expand All @@ -46,21 +47,25 @@ import VerificationNeededTag from './VerificationNeededTag';
interface Props {
style?: ViewStyle;
action: Action;
canUserPerformAction: boolean;
}

const ActionCard: FC<Props> = ({ style, action, canUserPerformAction }) => {
const { userProgress } = useSnapshot(loyaltyState);
const ActionCard: FC<Props> = ({ style, action }) => {
const { userProgress, typeActionMap } = useSnapshot(loyaltyState);
const { name, desc, icon, ctaText, ctaType, cta } = useMemo(() => {
return extractDataFromMetadata(action.metadata as ActionMetadata[]);
}, [action]);

const [isDoingAction, setIsDoingAction] = useState(false);

const canUserDoAction = checkIfUserCanDoAction(
userProgress as UserProgress,
action,
);

const initialTimeRemaining = useMemo<number | null>(() => {
if (
!userProgress ||
canUserPerformAction ||
canUserDoAction ||
action.category !== ActionCategory.Recurring ||
!action.cycleInHours
) {
Expand All @@ -82,6 +87,32 @@ const ActionCard: FC<Props> = ({ style, action, canUserPerformAction }) => {
return cycleEndTime.getTime() - Date.now();
}, [userProgress]);

const isRecorded = useMemo(() => {
if (!userProgress?.actionRecords) return false;

const relatedRecurringAction = typeActionMap
.get(action.type!)
?.find((a) => a.category === ActionCategory.Recurring);

if (relatedRecurringAction?.cycleInHours) {
const lastRecord = userProgress.actionRecords.findLast(
(record) => record!.actionId === relatedRecurringAction.id,
);
if (!lastRecord) {
return false;
}

const cycleEndTime = getCycleEndTime(
new Date(lastRecord.timestamp),
relatedRecurringAction.cycleInHours,
);

return new Date() < cycleEndTime;
}

return false;
}, [action, userProgress, typeActionMap]);

const handleDoAction = async () => {
if (ctaType === 'internal') {
navigateInternalByCta(cta);
Expand Down Expand Up @@ -169,7 +200,7 @@ const ActionCard: FC<Props> = ({ style, action, canUserPerformAction }) => {
}, [stat, action.streak]);

const isPassthrough =
!canUserPerformAction && action.category !== ActionCategory.Streak;
!canUserDoAction && action.category !== ActionCategory.Streak;

return (
<View style={[styles.container, style]}>
Expand Down Expand Up @@ -224,14 +255,14 @@ const ActionCard: FC<Props> = ({ style, action, canUserPerformAction }) => {
<StreakBar
streak={action.streak}
currentStreak={currentStreak}
isRecorded={!canUserPerformAction}
style={{ marginLeft: 8, flexGrow: 1 }}
isRecorded={isRecorded}
style={styles.streakBarContainer}
/>
)}
</View>
</View>

{canUserPerformAction &&
{canUserDoAction &&
action.category !== ActionCategory.Milestone &&
action.category !== ActionCategory.Streak &&
(isDoingAction ? (
Expand Down Expand Up @@ -309,6 +340,10 @@ const styles = StyleSheet.create({
paddingVertical: 8,
paddingHorizontal: 20,
},
streakBarContainer: {
marginLeft: 8,
flexGrow: 1,
},
});

export default ActionCard;
10 changes: 1 addition & 9 deletions apps/wallet/src/features/Loyalty/PartnerTab/PartnerQuest.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { FC } from 'react';
import type { ViewStyle } from 'react-native';
import { ScrollView, StyleSheet } from 'react-native';
import type { Action, UserProgress } from '@walless/graphql';
import type { Action } from '@walless/graphql';
import type { ModalConfigs } from '@walless/gui';
import {
AnimateDirections,
Expand All @@ -10,13 +10,10 @@ import {
SwipeDownGesture,
} from '@walless/gui';
import { ModalId } from 'modals/types';
import { loyaltyState } from 'state/loyalty';
import { useSafeAreaInsets } from 'utils/hooks';
import { useSnapshot } from 'valtio';

import ActionCard from '../ActionCard';
import ModalHeader from '../components/ModalHeader';
import { canUserPerformAction } from '../internal';

interface PartnerQuestProps {
partner: string;
Expand All @@ -28,7 +25,6 @@ type Props = PartnerQuestProps & {
};

const PartnerQuestModal: FC<Props> = ({ config, partner, actions }) => {
const { userProgress } = useSnapshot(loyaltyState);
const safeAreaInsets = useSafeAreaInsets();

const safeAreaStyle: ViewStyle = {
Expand All @@ -55,10 +51,6 @@ const PartnerQuestModal: FC<Props> = ({ config, partner, actions }) => {
<ActionCard
key={action.id}
action={action as Action}
canUserPerformAction={canUserPerformAction(
userProgress as UserProgress,
action as Action,
)}
style={{
marginBottom: index !== actions.length - 1 ? 8 : 0,
}}
Expand Down
14 changes: 3 additions & 11 deletions apps/wallet/src/features/Loyalty/WallessTab/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { StyleSheet, View } from 'react-native';
import type { Action, UserProgress } from '@walless/graphql';
import type { Action } from '@walless/graphql';
import { Text } from '@walless/gui';
import { loyaltyState } from 'state/loyalty';
import { useSnapshot } from 'utils/hooks';

import ActionCard from '../ActionCard';
import { canUserPerformAction } from '../internal';

const WallessTab = () => {
const { userProgress, wallessActions } = useSnapshot(loyaltyState);
const { wallessActions } = useSnapshot(loyaltyState);

return (
<View style={styles.container}>
Expand All @@ -21,14 +20,7 @@ const WallessTab = () => {
)}

{wallessActions.map((action) => (
<ActionCard
key={action.id}
action={action as Action}
canUserPerformAction={canUserPerformAction(
userProgress as UserProgress,
action as Action,
)}
/>
<ActionCard key={action.id} action={action as Action} />
))}
</View>
);
Expand Down
10 changes: 10 additions & 0 deletions apps/wallet/src/features/Loyalty/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,21 @@ const LoyaltyFeature = () => {

const wallessActions: Action[] = [];
const partnerActionMap: Map<string, Action[]> = new Map();
const typeActionMap: Map<string, Action[]> = new Map();

sortedActions.forEach((action) => {
if (!action.type) return;

const extractedMetadata = extractDataFromMetadata(
action.metadata as ActionMetadata[],
);

if (typeActionMap.has(action.type)) {
typeActionMap.get(action.type)!.push(action);
} else {
typeActionMap.set(action.type, [action]);
}

if (extractedMetadata.partner === '') {
wallessActions.push(action);
} else if (partnerActionMap.has(extractedMetadata.partner)) {
Expand All @@ -84,6 +93,7 @@ const LoyaltyFeature = () => {

loyaltyActions.setWallessActions(wallessActions);
loyaltyActions.setPartnerActionMap(partnerActionMap);
loyaltyActions.setTypeActionMap(typeActionMap);
} catch (err) {
console.error(err);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/wallet/src/features/Loyalty/internal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ export const formatCountdownTime = (timeRemaining: number) => {
return `${hours}h:${minutes}m:${seconds}s`;
};

export const canUserPerformAction = (
export const checkIfUserCanDoAction = (
userProgress: UserProgress,
action: Action,
) => {
Expand Down
3 changes: 3 additions & 0 deletions apps/wallet/src/state/loyalty/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ export const loyaltyActions = {
setPartnerActionMap: (map: Map<string, Action[]>) => {
loyaltyState.partnerActionMap = map;
},
setTypeActionMap: (map: Map<string, Action[]>) => {
loyaltyState.typeActionMap = map;
},
};

export * from './internal';
2 changes: 2 additions & 0 deletions apps/wallet/src/state/loyalty/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ export interface LoyaltyState {
userProgress?: UserProgress;
wallessActions: Action[];
partnerActionMap: Map<string, Action[]>;
typeActionMap: Map<string, Action[]>;
}

export const loyaltyState = proxy<LoyaltyState>({
wallessActions: [],
partnerActionMap: new Map(),
typeActionMap: new Map(),
});
Loading