367 lines
8.5 KiB
TypeScript
367 lines
8.5 KiB
TypeScript
/**
|
|
* In-memory data store for MVP implementation
|
|
*/
|
|
|
|
import {
|
|
User,
|
|
Transaction,
|
|
Task,
|
|
UserTask,
|
|
Badge,
|
|
UserBadge,
|
|
Quiz,
|
|
Referral,
|
|
TaskType,
|
|
RequirementType,
|
|
TransactionType
|
|
} from '../types';
|
|
|
|
// In-memory storage
|
|
const users: User[] = [];
|
|
const transactions: Transaction[] = [];
|
|
const tasks: Task[] = [];
|
|
const userTasks: UserTask[] = [];
|
|
const badges: Badge[] = [];
|
|
const userBadges: UserBadge[] = [];
|
|
const quizzes: Quiz[] = [];
|
|
const referrals: Referral[] = [];
|
|
|
|
// ID generators
|
|
let userIdCounter = 1;
|
|
let transactionIdCounter = 1;
|
|
let taskIdCounter = 1;
|
|
let userTaskIdCounter = 1;
|
|
let badgeIdCounter = 1;
|
|
let userBadgeIdCounter = 1;
|
|
let quizIdCounter = 1;
|
|
let referralIdCounter = 1;
|
|
|
|
// Helper: Generate IDs
|
|
const generateId = (prefix: string, counter: number): string =>
|
|
`${prefix}_${String(counter).padStart(6, '0')}`;
|
|
|
|
// User operations
|
|
export const findUser = (id: string): User | undefined => {
|
|
return users.find(u => u.id === id);
|
|
};
|
|
|
|
export const findUserByEmail = (email: string): User | undefined => {
|
|
return users.find(u => u.email.toLowerCase() === email.toLowerCase());
|
|
};
|
|
|
|
export const createUser = (email: string, passwordHash: string, name: string): User => {
|
|
const user: User = {
|
|
id: generateId('user', userIdCounter++),
|
|
email,
|
|
passwordHash,
|
|
name,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date()
|
|
};
|
|
users.push(user);
|
|
return user;
|
|
};
|
|
|
|
export const updateUser = (id: string, updates: Partial<User>): User | null => {
|
|
const user = findUser(id);
|
|
if (!user) return null;
|
|
|
|
Object.assign(user, { ...updates, updatedAt: new Date() });
|
|
return user;
|
|
};
|
|
|
|
export const getAllUsers = (): User[] => {
|
|
return [...users];
|
|
};
|
|
|
|
// Transaction operations
|
|
export const createTransaction = (
|
|
userId: string,
|
|
amount: number,
|
|
type: TransactionType,
|
|
source: string
|
|
): Transaction => {
|
|
const transaction: Transaction = {
|
|
id: generateId('txn', transactionIdCounter++),
|
|
userId,
|
|
amount,
|
|
type,
|
|
source,
|
|
createdAt: new Date()
|
|
};
|
|
transactions.push(transaction);
|
|
return transaction;
|
|
};
|
|
|
|
export const getUserTransactions = (userId: string): Transaction[] => {
|
|
return transactions.filter(t => t.userId === userId);
|
|
};
|
|
|
|
export const getUserBalance = (userId: string): number => {
|
|
const userTxns = getUserTransactions(userId);
|
|
return userTxns.reduce((balance, txn) => {
|
|
return txn.type === TransactionType.EARNED
|
|
? balance + txn.amount
|
|
: balance - txn.amount;
|
|
}, 0);
|
|
};
|
|
|
|
// Task operations
|
|
export const findTask = (id: string): Task | undefined => {
|
|
return tasks.find(t => t.id === id);
|
|
};
|
|
|
|
export const getActiveTasks = (): Task[] => {
|
|
return tasks.filter(t => t.isActive);
|
|
};
|
|
|
|
export const createTask = (task: Omit<Task, 'id' | 'createdAt' | 'updatedAt'>): Task => {
|
|
const newTask: Task = {
|
|
...task,
|
|
id: generateId('task', taskIdCounter++),
|
|
createdAt: new Date(),
|
|
updatedAt: new Date()
|
|
};
|
|
tasks.push(newTask);
|
|
return newTask;
|
|
};
|
|
|
|
// UserTask operations
|
|
export const createUserTask = (
|
|
userId: string,
|
|
taskId: string,
|
|
pointsEarned: number
|
|
): UserTask => {
|
|
const userTask: UserTask = {
|
|
id: generateId('utask', userTaskIdCounter++),
|
|
userId,
|
|
taskId,
|
|
completedAt: new Date(),
|
|
pointsEarned
|
|
};
|
|
userTasks.push(userTask);
|
|
return userTask;
|
|
};
|
|
|
|
export const getUserCompletedTasks = (userId: string): UserTask[] => {
|
|
return userTasks.filter(ut => ut.userId === userId);
|
|
};
|
|
|
|
export const hasUserCompletedTask = (userId: string, taskId: string): boolean => {
|
|
return userTasks.some(ut => ut.userId === userId && ut.taskId === taskId);
|
|
};
|
|
|
|
// Badge operations
|
|
export const findBadge = (id: string): Badge | undefined => {
|
|
return badges.find(b => b.id === id);
|
|
};
|
|
|
|
export const getAllBadges = (): Badge[] => {
|
|
return [...badges];
|
|
};
|
|
|
|
export const createBadge = (badge: Omit<Badge, 'id'>): Badge => {
|
|
const newBadge: Badge = {
|
|
...badge,
|
|
id: generateId('badge', badgeIdCounter++)
|
|
};
|
|
badges.push(newBadge);
|
|
return newBadge;
|
|
};
|
|
|
|
// UserBadge operations
|
|
export const createUserBadge = (userId: string, badgeId: string): UserBadge => {
|
|
const userBadge: UserBadge = {
|
|
id: generateId('ubadge', userBadgeIdCounter++),
|
|
userId,
|
|
badgeId,
|
|
earnedAt: new Date()
|
|
};
|
|
userBadges.push(userBadge);
|
|
return userBadge;
|
|
};
|
|
|
|
export const getUserBadges = (userId: string): UserBadge[] => {
|
|
return userBadges.filter(ub => ub.userId === userId);
|
|
};
|
|
|
|
export const hasUserEarnedBadge = (userId: string, badgeId: string): boolean => {
|
|
return userBadges.some(ub => ub.userId === userId && ub.badgeId === badgeId);
|
|
};
|
|
|
|
// Quiz operations
|
|
export const findQuiz = (id: string): Quiz | undefined => {
|
|
return quizzes.find(q => q.id === id);
|
|
};
|
|
|
|
export const findQuizByTaskId = (taskId: string): Quiz | undefined => {
|
|
return quizzes.find(q => q.taskId === taskId);
|
|
};
|
|
|
|
export const createQuiz = (quiz: Omit<Quiz, 'id'>): Quiz => {
|
|
const newQuiz: Quiz = {
|
|
...quiz,
|
|
id: generateId('quiz', quizIdCounter++)
|
|
};
|
|
quizzes.push(newQuiz);
|
|
return newQuiz;
|
|
};
|
|
|
|
// Referral operations
|
|
export const createReferral = (
|
|
referrerId: string,
|
|
referredId: string,
|
|
bonusPoints: number
|
|
): Referral => {
|
|
const referral: Referral = {
|
|
id: generateId('ref', referralIdCounter++),
|
|
referrerId,
|
|
referredId,
|
|
bonusPoints,
|
|
createdAt: new Date()
|
|
};
|
|
referrals.push(referral);
|
|
return referral;
|
|
};
|
|
|
|
export const getUserReferrals = (userId: string): Referral[] => {
|
|
return referrals.filter(r => r.referrerId === userId);
|
|
};
|
|
|
|
// Seed data
|
|
export const seedDatabase = () => {
|
|
// Clear existing data
|
|
users.length = 0;
|
|
transactions.length = 0;
|
|
tasks.length = 0;
|
|
userTasks.length = 0;
|
|
badges.length = 0;
|
|
userBadges.length = 0;
|
|
quizzes.length = 0;
|
|
referrals.length = 0;
|
|
|
|
// Reset counters
|
|
userIdCounter = 1;
|
|
transactionIdCounter = 1;
|
|
taskIdCounter = 1;
|
|
userTaskIdCounter = 1;
|
|
badgeIdCounter = 1;
|
|
userBadgeIdCounter = 1;
|
|
quizIdCounter = 1;
|
|
referralIdCounter = 1;
|
|
|
|
// Seed tasks
|
|
const dailyCheckin = createTask({
|
|
type: TaskType.CHECKIN,
|
|
title: 'Daily Check-in',
|
|
description: 'Check in daily to earn points',
|
|
pointsReward: 10,
|
|
isActive: true
|
|
});
|
|
|
|
const watchAd = createTask({
|
|
type: TaskType.AD,
|
|
title: 'Watch Advertisement',
|
|
description: 'Watch a short video ad',
|
|
pointsReward: 5,
|
|
isActive: true
|
|
});
|
|
|
|
const takeSurvey = createTask({
|
|
type: TaskType.SURVEY,
|
|
title: 'Complete Survey',
|
|
description: 'Share your opinion in a quick survey',
|
|
pointsReward: 20,
|
|
isActive: true
|
|
});
|
|
|
|
const quizTask = createTask({
|
|
type: TaskType.QUIZ,
|
|
title: 'General Knowledge Quiz',
|
|
description: 'Test your knowledge and earn points',
|
|
pointsReward: 15,
|
|
isActive: true
|
|
});
|
|
|
|
const videoTask = createTask({
|
|
type: TaskType.VIDEO,
|
|
title: 'Watch Educational Video',
|
|
description: 'Watch a 5-minute educational video',
|
|
pointsReward: 8,
|
|
isActive: true
|
|
});
|
|
|
|
const readingTask = createTask({
|
|
type: TaskType.READING,
|
|
title: 'Read Article',
|
|
description: 'Read an interesting article',
|
|
pointsReward: 12,
|
|
isActive: true
|
|
});
|
|
|
|
// Seed quiz for quiz task
|
|
createQuiz({
|
|
taskId: quizTask.id,
|
|
question: 'What is the capital of France?',
|
|
options: ['London', 'Berlin', 'Paris', 'Madrid'],
|
|
correctAnswer: 2
|
|
});
|
|
|
|
// Seed badges
|
|
createBadge({
|
|
name: 'First Steps',
|
|
description: 'Complete your first task',
|
|
icon: '🎯',
|
|
requirementType: RequirementType.TASKS_COMPLETED,
|
|
requirementValue: 1
|
|
});
|
|
|
|
createBadge({
|
|
name: 'Point Collector',
|
|
description: 'Earn 100 points',
|
|
icon: '💰',
|
|
requirementType: RequirementType.POINTS_TOTAL,
|
|
requirementValue: 100
|
|
});
|
|
|
|
createBadge({
|
|
name: 'Dedicated',
|
|
description: 'Complete 10 tasks',
|
|
icon: '⭐',
|
|
requirementType: RequirementType.TASKS_COMPLETED,
|
|
requirementValue: 10
|
|
});
|
|
|
|
createBadge({
|
|
name: 'Week Warrior',
|
|
description: 'Maintain a 7-day streak',
|
|
icon: '🔥',
|
|
requirementType: RequirementType.STREAK_DAYS,
|
|
requirementValue: 7
|
|
});
|
|
|
|
createBadge({
|
|
name: 'Referral Master',
|
|
description: 'Refer 5 friends',
|
|
icon: '🤝',
|
|
requirementType: RequirementType.REFERRALS,
|
|
requirementValue: 5
|
|
});
|
|
|
|
createBadge({
|
|
name: 'Point Millionaire',
|
|
description: 'Earn 1000 points',
|
|
icon: '💎',
|
|
requirementType: RequirementType.POINTS_TOTAL,
|
|
requirementValue: 1000
|
|
});
|
|
|
|
console.log('Database seeded successfully');
|
|
console.log(`- ${tasks.length} tasks`);
|
|
console.log(`- ${badges.length} badges`);
|
|
console.log(`- ${quizzes.length} quizzes`);
|
|
};
|
|
|
|
// Initialize seed data
|
|
seedDatabase();
|