This commit is contained in:
degradin 2025-03-16 11:53:27 +03:00
parent 5a252f6f29
commit 66ff498fa0
5 changed files with 111 additions and 23 deletions

6
.env
View File

@ -1,5 +1,6 @@
MONGODB_URI=mongodb://localhost:27017/campfire MONGODB_URI=mongodb://localhost:27017/campfire
JWT_SECRET=your-super-secret-key-change-in-production JWT_SECRET=your-super-secret-key-change-in-production
<<<<<<< Updated upstream
PORT=3000 PORT=3000
# Telegram Bot # Telegram Bot
TELEGRAM_BOT_TOKEN=7641998551:AAF_2-av1rUy_-icQ1fsfHOyYBGFt8cEmE4 TELEGRAM_BOT_TOKEN=7641998551:AAF_2-av1rUy_-icQ1fsfHOyYBGFt8cEmE4
@ -12,4 +13,9 @@ JWT_SECRET=your_jwt_secret_here
# App # App
NEXT_PUBLIC_APP_URL=http://localhost:3000 NEXT_PUBLIC_APP_URL=http://localhost:3000
=======
PORT=3001
NEXT_PUBLIC_URL=http://localhost:3000
NEXT_PUBLIC_API_URL=http://localhost:3001/api
>>>>>>> Stashed changes
NODE_ENV=development NODE_ENV=development

View File

@ -2,21 +2,54 @@ import axios from 'axios';
const api = axios.create({ const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL, baseURL: process.env.NEXT_PUBLIC_API_URL,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
},
timeout: 10000, // 10 секунд таймаут
}); });
// Интерцептор для добавления токена к запросам // Интерцептор для добавления токена к запросам
api.interceptors.request.use((config) => { api.interceptors.request.use((config) => {
const token = localStorage.getItem('token'); if (typeof window !== 'undefined') {
if (token) { const token = localStorage.getItem('token');
config.headers.Authorization = `Bearer ${token}`; if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
} }
return config; return config;
}, (error) => {
return Promise.reject(error);
}); });
// Интерцептор для обработки ошибок
api.interceptors.response.use(
(response) => response,
(error) => {
if (error.response) {
// Ошибка от сервера
return Promise.reject(error.response.data);
} else if (error.request) {
// Ошибка сети
return Promise.reject({ error: 'Ошибка сети. Проверьте подключение к интернету.' });
} else {
// Другие ошибки
return Promise.reject({ error: 'Произошла ошибка при выполнении запроса.' });
}
}
);
export const auth = async (telegramId: string, username: string) => { export const auth = async (telegramId: string, username: string) => {
const response = await api.post('/auth', { telegramId, username }); try {
localStorage.setItem('token', response.data.token); const response = await api.post('/auth', { telegramId, username });
return response.data; if (typeof window !== 'undefined') {
localStorage.setItem('token', response.data.token);
}
return response.data;
} catch (error) {
console.error('Auth error:', error);
throw error;
}
}; };
export const getProfile = async () => { export const getProfile = async () => {

View File

@ -2,6 +2,7 @@ import express from 'express';
import mongoose from 'mongoose'; import mongoose from 'mongoose';
import dotenv from 'dotenv'; import dotenv from 'dotenv';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import cors from 'cors';
import User, { IUser } from './models/User'; import User, { IUser } from './models/User';
import ShopItem from './models/ShopItem'; import ShopItem from './models/ShopItem';
@ -20,6 +21,12 @@ declare global {
} }
const app = express(); const app = express();
// Middleware
app.use(cors({
origin: process.env.NEXT_PUBLIC_URL || 'http://localhost:3000',
credentials: true
}));
app.use(express.json()); app.use(express.json());
// Подключение к MongoDB // Подключение к MongoDB
@ -45,11 +52,24 @@ const authenticateToken = (req: express.Request, res: express.Response, next: ex
}); });
}; };
// Обработка ошибок
const errorHandler = (err: any, req: express.Request, res: express.Response, next: express.NextFunction) => {
console.error(err.stack);
res.status(500).json({
error: 'Ошибка сервера',
message: process.env.NODE_ENV === 'development' ? err.message : undefined
});
};
// Регистрация/авторизация пользователя // Регистрация/авторизация пользователя
app.post('/api/auth', async (req, res) => { app.post('/api/auth', async (req, res, next) => {
try { try {
const { telegramId, username } = req.body; const { telegramId, username } = req.body;
if (!telegramId || !username) {
return res.status(400).json({ error: 'Отсутствуют обязательные поля' });
}
let user = await User.findOne({ telegramId }); let user = await User.findOne({ telegramId });
if (!user) { if (!user) {
@ -70,7 +90,7 @@ app.post('/api/auth', async (req, res) => {
res.json({ token, user }); res.json({ token, user });
} catch (error) { } catch (error) {
res.status(500).json({ error: 'Ошибка сервера' }); next(error);
} }
}); });
@ -178,6 +198,9 @@ app.post('/api/transfer', authenticateToken, async (req, res) => {
} }
}); });
// Добавляем обработчик ошибок в конце
app.use(errorHandler);
const PORT = process.env.PORT || 3001; const PORT = process.env.PORT || 3001;
app.listen(PORT, () => { app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`); console.log(`Server is running on port ${PORT}`);

24
package-lock.json generated
View File

@ -12,8 +12,10 @@
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"@twa-dev/sdk": "^6.9.0", "@twa-dev/sdk": "^6.9.0",
"@types/cors": "^2.8.17",
"axios": "^1.5.1", "axios": "^1.5.1",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"express": "^4.18.2", "express": "^4.18.2",
"framer-motion": "^10.16.4", "framer-motion": "^10.16.4",
@ -1152,6 +1154,15 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/cors": {
"version": "2.8.17",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
"integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/express": { "node_modules/@types/express": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
@ -2171,6 +2182,19 @@
"toggle-selection": "^1.0.6" "toggle-selection": "^1.0.6"
} }
}, },
"node_modules/cors": {
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
"license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/cosmiconfig": { "node_modules/cosmiconfig": {
"version": "7.1.0", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",

View File

@ -9,28 +9,30 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"next": "^13.5.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@twa-dev/sdk": "^6.9.0",
"mongoose": "^7.5.3",
"express": "^4.18.2",
"jsonwebtoken": "^9.0.2",
"bcryptjs": "^2.4.3",
"dotenv": "^16.3.1",
"axios": "^1.5.1",
"@chakra-ui/react": "^2.8.1", "@chakra-ui/react": "^2.8.1",
"@emotion/react": "^11.11.1", "@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0", "@emotion/styled": "^11.11.0",
"framer-motion": "^10.16.4" "@twa-dev/sdk": "^6.9.0",
"@types/cors": "^2.8.17",
"axios": "^1.5.1",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"framer-motion": "^10.16.4",
"jsonwebtoken": "^9.0.2",
"mongoose": "^7.5.3",
"next": "^13.5.4",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}, },
"devDependencies": { "devDependencies": {
"typescript": "^5.2.2",
"@types/react": "^18.2.25",
"@types/node": "^20.8.3",
"@types/express": "^4.17.18", "@types/express": "^4.17.18",
"@types/node": "^20.8.3",
"@types/react": "^18.2.25",
"eslint": "^8.51.0", "eslint": "^8.51.0",
"eslint-config-next": "13.5.4", "eslint-config-next": "13.5.4",
"prettier": "^3.0.3" "prettier": "^3.0.3",
"typescript": "^5.2.2"
} }
} }