Amba-Agent-App/lib/services/pointsService.ts
2026-01-16 00:22:35 +03:00

174 lines
3.8 KiB
TypeScript

import AsyncStorage from "@react-native-async-storage/async-storage";
export type PointsActivityType =
| "contact_sync"
| "send_money"
| "login"
| "purchase_ticket"
| "add_recipient"
| "share_event"
| "make_request"
| "referral_link";
export interface PointsActivityEntry {
id: string;
type: PointsActivityType;
points: number;
timestamp: string;
metadata?: Record<string, any>;
}
export interface PointsState {
total: number;
activities: PointsActivityEntry[];
}
const STORAGE_KEY = "user_points";
const DEFAULT_STATE: PointsState = {
total: 0,
activities: [],
};
export const POINT_VALUES: Record<PointsActivityType, number> = {
contact_sync: 10,
send_money: 10,
login: 5,
purchase_ticket: 15,
add_recipient: 10,
share_event: 5,
make_request: 8,
referral_link: 20,
};
async function loadState(): Promise<PointsState> {
try {
const stored = await AsyncStorage.getItem(STORAGE_KEY);
if (!stored) return DEFAULT_STATE;
const parsed = JSON.parse(stored);
if (
typeof parsed === "object" &&
parsed !== null &&
typeof parsed.total === "number" &&
Array.isArray(parsed.activities)
) {
return parsed as PointsState;
}
return DEFAULT_STATE;
} catch (error) {
if (__DEV__) {
console.warn("[pointsService] Failed to load state", error);
}
return DEFAULT_STATE;
}
}
async function saveState(state: PointsState): Promise<void> {
try {
await AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch (error) {
if (__DEV__) {
console.warn("[pointsService] Failed to save state", error);
}
}
}
export async function getPointsState(): Promise<PointsState> {
return loadState();
}
export async function awardPoints(
type: PointsActivityType,
metadata?: Record<string, any>
): Promise<PointsState> {
const current = await loadState();
const delta = POINT_VALUES[type] ?? 0;
const entry: PointsActivityEntry = {
id: `${type}-${Date.now()}`,
type,
points: delta,
timestamp: new Date().toISOString(),
metadata,
};
const next: PointsState = {
total: current.total + delta,
activities: [entry, ...current.activities],
};
await saveState(next);
return next;
}
const LOGIN_LAST_AWARD_KEY = "user_points_login_last_award";
const CONTACT_SYNC_AWARDED_KEY = "user_points_contact_sync_awarded";
export async function awardDailyLoginPoints(
metadata?: Record<string, any>
): Promise<PointsState> {
const today = new Date().toISOString().slice(0, 10);
try {
const lastAwardDate = await AsyncStorage.getItem(LOGIN_LAST_AWARD_KEY);
if (lastAwardDate === today) {
return loadState();
}
} catch (error) {
if (__DEV__) {
console.warn(
"[pointsService] Failed to read last login award date",
error
);
}
}
const updatedState = await awardPoints("login", metadata);
try {
await AsyncStorage.setItem(LOGIN_LAST_AWARD_KEY, today);
} catch (error) {
if (__DEV__) {
console.warn(
"[pointsService] Failed to save last login award date",
error
);
}
}
return updatedState;
}
export async function awardFirstContactSyncPoints(
metadata?: Record<string, any>
): Promise<PointsState> {
try {
const alreadyAwarded = await AsyncStorage.getItem(CONTACT_SYNC_AWARDED_KEY);
if (alreadyAwarded === "true") {
return loadState();
}
} catch (error) {
if (__DEV__) {
console.warn(
"[pointsService] Failed to read contact sync awarded flag",
error
);
}
}
const updatedState = await awardPoints("contact_sync", metadata);
try {
await AsyncStorage.setItem(CONTACT_SYNC_AWARDED_KEY, "true");
} catch (error) {
if (__DEV__) {
console.warn(
"[pointsService] Failed to save contact sync awarded flag",
error
);
}
}
return updatedState;
}