Initial commit: Tapalka monorepo (bot, front, strapi)

This commit is contained in:
2026-05-21 11:54:44 +07:00
commit 9ec9485940
208 changed files with 58314 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
import { AxiosInstance } from 'axios';
import { HttpInstanceFactory } from '@/utils/HttpInstanceFactory';
import { IPlayer } from '@/interfaces/player.type';
import { IExchangeRequest } from '@/api/exchange-request.api';
export interface IArchiveRequest {
id: number;
attributes: {
player: IPlayer;
exchange_requests: { data: IExchangeRequest[] };
rejected_requests: { data: IExchangeRequest[] };
};
}
export class ArchiveRequestApi {
private static instance: ArchiveRequestApi | null = null;
private httpInstance: AxiosInstance;
private constructor(token: string) {
this.httpInstance = HttpInstanceFactory.updateAuthorizedInstance(token);
}
public static getInstance(token: string): ArchiveRequestApi {
if (this.instance) return this.instance;
this.instance = new ArchiveRequestApi(token);
return this.instance;
}
async createArchiveRequest(playerId: number): Promise<IArchiveRequest> {
return (
await this.httpInstance.post<IArchiveRequest>(`/archive-requests`, {
data: {
player: {
connect: [{ id: playerId }],
},
},
})
).data;
}
}

View File

@@ -0,0 +1,34 @@
import { AxiosInstance } from 'axios';
import { HttpInstanceFactory } from '../utils/HttpInstanceFactory';
export interface IUser {
jwt: string;
user: {
id: number;
username: string;
confirmed: boolean;
blocked: boolean;
}
}
export class AuthApi {
private static instance: AuthApi | null = null;
private httpInstance: AxiosInstance;
private constructor() {
this.httpInstance = HttpInstanceFactory.getBaseInstance();
}
public static getInstance(): AuthApi {
if (this.instance) return this.instance;
this.instance = new AuthApi();
return this.instance;
}
async login(): Promise<IUser> {
return (await this.httpInstance.post<IUser>(`/auth/local`, {
identifier: process.env.NEXT_PUBLIC_STRAPI_USER,
password: process.env.NEXT_PUBLIC_STRAPI_PASSWORD,
})).data;
}
}

View File

@@ -0,0 +1,42 @@
import axios, { AxiosInstance } from 'axios';
export interface IConfigBot {
token: string;
dateLifetimeJwt: Date;
}
export interface IBotLink {
link: string;
}
export class ConfigBotApi {
private static instance: ConfigBotApi | null = null;
private httpBotInstance: AxiosInstance;
private constructor() {
const isServer = typeof window === 'undefined';
const baseURL = isServer
? 'http://127.0.0.1:3001'
: process.env.NEXT_PUBLIC_BOT_API;
this.httpBotInstance = axios.create({
baseURL,
headers: {
'ngrok-skip-browser-warning': 'true',
},
});
}
public static getInstance(): ConfigBotApi {
if (this.instance) return this.instance;
this.instance = new ConfigBotApi();
return this.instance;
}
async getConfigBot(): Promise<IConfigBot> {
return (await this.httpBotInstance.get<IConfigBot>(`/config-bot-data`)).data;
}
async getBotLink(): Promise<IBotLink> {
return (await this.httpBotInstance.get<IBotLink>(`/link-bot`)).data;
}
}

View File

@@ -0,0 +1,33 @@
import { AxiosInstance } from 'axios';
import { HttpInstanceFactory } from '@/utils/HttpInstanceFactory';
import { IPlayer } from '@/interfaces/player.type';
export interface IConfig {
id: number;
attributes: {
farm_amount: number;
farming_time: number;
admins: { data: IPlayer[] };
};
}
export class ConfigApi {
private static instance: ConfigApi | null = null;
private httpInstance: AxiosInstance;
private constructor(token: string, shouldUpdateInstance: boolean = false) {
this.httpInstance = HttpInstanceFactory.getAuthorizedInstance(token);
}
public static getInstance(token: string, shouldUpdateInstance: boolean = false): ConfigApi {
if (!shouldUpdateInstance && this.instance) {
return this.instance;
}
this.instance = new ConfigApi(token);
return this.instance;
}
async getConfig(): Promise<{ data: IConfig }> {
return (await this.httpInstance.get<{ data: IConfig }>(`/config?populate=*`)).data;
}
}

View File

@@ -0,0 +1,82 @@
import axios, { AxiosInstance } from 'axios';
import { HttpInstanceFactory } from '@/utils/HttpInstanceFactory';
import { IPlayer } from '@/interfaces/player.type';
import { toFixed } from '@/utils/FormatNumber';
export interface IExchangeCreate {
amount: number;
total: number;
playerId: number;
nickname: string;
balance: number;
telegram_id: string[] | number[];
shop_item?: number;
archive_request_id: number;
}
export interface IExchangeRequest {
id: number;
attributes: {
amount: number;
total: number;
player: { data: IPlayer };
roblox_nick: string;
status: 'done' | 'rejected' | 'pending';
};
}
export class ExchangeRequestApi {
private static instance: ExchangeRequestApi | null = null;
private httpInstance: AxiosInstance;
private httpBotInstance: AxiosInstance;
private constructor(token: string) {
this.httpInstance = HttpInstanceFactory.updateAuthorizedInstance(token);
this.httpBotInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_BOT_API,
headers: {
'Content-Type': 'application/json',
},
});
}
public static getInstance(token: string): ExchangeRequestApi {
if (this.instance) return this.instance;
this.instance = new ExchangeRequestApi(token);
return this.instance;
}
async createExchange(data: IExchangeCreate): Promise<IExchangeRequest> {
const res = (
await this.httpInstance.post<{ data: IExchangeRequest }>(
`/exchange-requests?populate=*`,
{
data: {
amount: toFixed(data.amount),
total: toFixed(data.total),
roblox_nick: data.nickname,
status: 'pending',
shop_item: data.shop_item ? data.shop_item : null,
},
},
)
).data.data;
if (res) {
await this.httpInstance.put(`/archive-requests/${data.archive_request_id}`, {
data: {
exchange_requests: {
connect: [res.id],
},
},
});
await this.httpInstance.put(`/players/${data.playerId}`, {
data: { balance: toFixed(data.balance - data.amount) },
});
await this.httpBotInstance.post(`/notify`, {
telegram_id: data.telegram_id,
exchange_id: res.id,
});
}
return res;
}
}

View File

@@ -0,0 +1,56 @@
import { AxiosInstance } from 'axios';
import { HttpInstanceFactory } from '@/utils/HttpInstanceFactory';
import { IPlayer, IUpdatePlayerTask } from '@/interfaces/player.type';
export class PlayerApi {
private static instance: PlayerApi | null = null;
private httpInstance: AxiosInstance;
private populateString: string =
'populate=archive_request.rejected_requests&populate=archive_request.exchange_requests&populate=finished_tasks.task.icon&populate=referral.my_referrals&populate=my_referrals.my_referrals';
private constructor(token?: string) {
this.httpInstance = HttpInstanceFactory.getAuthorizedInstance(token);
}
public static getInstance(token?: string): PlayerApi {
if (this.instance) return this.instance;
this.instance = new PlayerApi(token);
return this.instance;
}
async findPlayerByAuthId(authId: string): Promise<IPlayer | null> {
const filteredPlayers: IPlayer[] = (
await this.httpInstance.get(
`/players/?filters[auth_id]=${authId}&${this.populateString}`,
)
).data.data;
return filteredPlayers.length > 0 ? filteredPlayers[0] : null;
}
async startFarm(startFarm: Date, playerId: number): Promise<IPlayer> {
return (
await this.httpInstance.put<{ data: IPlayer }>(
`/players/${playerId}?${this.populateString}`,
{
data: { start_farm: startFarm },
},
)
).data.data;
}
async claimRewards(playerId: number, balance: number): Promise<IPlayer> {
return (
await this.httpInstance.put<{ data: IPlayer }>(
`/players/${playerId}?${this.populateString}`,
{
data: { balance: balance, start_farm: null },
},
)
).data.data;
}
async updateTasks(playerId: number, data: IUpdatePlayerTask): Promise<IPlayer> {
return (await this.httpInstance.put<IPlayer>(`/players/finished-tasks/${playerId}`, data))
.data;
}
}

View File

@@ -0,0 +1,39 @@
import { AxiosInstance } from 'axios';
import { HttpInstanceFactory } from '@/utils/HttpInstanceFactory';
export interface IShopItem {
id: number;
attributes: {
isDecimal: boolean;
name: string;
price: number;
icon: {
data: {
id: number;
attributes: {
url: string;
};
};
};
};
}
export class ShopItemApi {
private static instance: ShopItemApi | null = null;
private httpInstance: AxiosInstance;
private constructor(token?: string) {
this.httpInstance = HttpInstanceFactory.getAuthorizedInstance(token);
}
public static getInstance(token?: string): ShopItemApi {
if (this.instance) return this.instance;
this.instance = new ShopItemApi(token);
return this.instance;
}
async getAllShopItems(): Promise<IShopItem[]> {
return (await this.httpInstance.get<{ data: IShopItem[] }>(`/shop-items?populate=*`)).data
.data;
}
}

View File

@@ -0,0 +1,38 @@
import { AxiosInstance } from 'axios';
import { HttpInstanceFactory } from '@/utils/HttpInstanceFactory';
export interface ITask {
id: number;
attributes: {
title: string;
link: string;
prize: number;
icon: {
data: {
id: number;
attributes: {
url: string;
};
};
};
};
}
export class TasksApi {
private static instance: TasksApi | null = null;
private httpInstance: AxiosInstance;
private constructor(token?: string) {
this.httpInstance = HttpInstanceFactory.getAuthorizedInstance(token);
}
public static getInstance(token?: string): TasksApi {
if (this.instance) return this.instance;
this.instance = new TasksApi(token);
return this.instance;
}
async getAllTasks(): Promise<ITask[]> {
return (await this.httpInstance.get<{ data: ITask[] }>(`/tasks?populate=*`)).data.data;
}
}