174 lines
3.8 KiB
TypeScript
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;
|
|
}
|