feat: implement complete Phase 2 frontend foundation with React 18
Major milestone: Frontend implementation complete for Shattered Void MMO FRONTEND IMPLEMENTATION: - React 18 + TypeScript + Vite development environment - Tailwind CSS with custom dark theme for sci-fi aesthetic - Zustand state management with authentication persistence - Socket.io WebSocket client with auto-reconnection - Protected routing with authentication guards - Responsive design with mobile-first approach AUTHENTICATION SYSTEM: - Login/register forms with comprehensive validation - JWT token management with localStorage persistence - Password strength validation and user feedback - Protected routes and authentication guards CORE GAME INTERFACE: - Colony management dashboard with real-time updates - Resource display with live production tracking - WebSocket integration for real-time game events - Navigation with connection status indicator - Toast notifications for user feedback BACKEND ENHANCEMENTS: - Complete Research System with technology tree (23 technologies) - Fleet Management System with ship designs and movement - Enhanced Authentication with email verification and password reset - Complete game tick integration for all systems - Advanced WebSocket events for real-time updates ARCHITECTURE FEATURES: - Type-safe TypeScript throughout - Component-based architecture with reusable UI elements - API client with request/response interceptors - Error handling and loading states - Performance optimized builds with code splitting Phase 2 Status: Frontend foundation complete (Week 1-2 objectives met) Ready for: Colony management, fleet operations, research interface Next: Enhanced gameplay features and admin interface 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
8d9ef427be
commit
d41d1e8125
130 changed files with 33588 additions and 14817 deletions
|
|
@ -14,55 +14,55 @@ const playerService = new PlayerService();
|
|||
* GET /api/player/dashboard
|
||||
*/
|
||||
const getDashboard = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
|
||||
logger.info('Player dashboard request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
logger.info('Player dashboard request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
});
|
||||
|
||||
// Get player profile with resources and stats
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
// Get player profile with resources and stats
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
|
||||
// TODO: Add additional dashboard data such as:
|
||||
// - Recent activities
|
||||
// - Colony summaries
|
||||
// - Fleet statuses
|
||||
// - Research progress
|
||||
// - Messages/notifications
|
||||
// TODO: Add additional dashboard data such as:
|
||||
// - Recent activities
|
||||
// - Colony summaries
|
||||
// - Fleet statuses
|
||||
// - Research progress
|
||||
// - Messages/notifications
|
||||
|
||||
const dashboardData = {
|
||||
player: profile,
|
||||
summary: {
|
||||
totalColonies: profile.stats.coloniesCount,
|
||||
totalFleets: profile.stats.fleetsCount,
|
||||
totalBattles: profile.stats.totalBattles,
|
||||
winRate: profile.stats.totalBattles > 0
|
||||
? Math.round((profile.stats.battlesWon / profile.stats.totalBattles) * 100)
|
||||
: 0
|
||||
},
|
||||
// Placeholder for future dashboard sections
|
||||
recentActivity: [],
|
||||
notifications: [],
|
||||
gameStatus: {
|
||||
online: true,
|
||||
lastTick: new Date().toISOString()
|
||||
}
|
||||
};
|
||||
const dashboardData = {
|
||||
player: profile,
|
||||
summary: {
|
||||
totalColonies: profile.stats.coloniesCount,
|
||||
totalFleets: profile.stats.fleetsCount,
|
||||
totalBattles: profile.stats.totalBattles,
|
||||
winRate: profile.stats.totalBattles > 0
|
||||
? Math.round((profile.stats.battlesWon / profile.stats.totalBattles) * 100)
|
||||
: 0,
|
||||
},
|
||||
// Placeholder for future dashboard sections
|
||||
recentActivity: [],
|
||||
notifications: [],
|
||||
gameStatus: {
|
||||
online: true,
|
||||
lastTick: new Date().toISOString(),
|
||||
},
|
||||
};
|
||||
|
||||
logger.info('Player dashboard data retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
username: profile.username
|
||||
});
|
||||
logger.info('Player dashboard data retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
username: profile.username,
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Dashboard data retrieved successfully',
|
||||
data: dashboardData,
|
||||
correlationId
|
||||
});
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Dashboard data retrieved successfully',
|
||||
data: dashboardData,
|
||||
correlationId,
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -70,32 +70,32 @@ const getDashboard = asyncHandler(async (req, res) => {
|
|||
* GET /api/player/resources
|
||||
*/
|
||||
const getResources = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
|
||||
logger.info('Player resources request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
logger.info('Player resources request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
});
|
||||
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
|
||||
logger.info('Player resources retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
scrap: profile.resources.scrap,
|
||||
energy: profile.resources.energy
|
||||
});
|
||||
logger.info('Player resources retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
scrap: profile.resources.scrap,
|
||||
energy: profile.resources.energy,
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Resources retrieved successfully',
|
||||
data: {
|
||||
resources: profile.resources,
|
||||
lastUpdated: new Date().toISOString()
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Resources retrieved successfully',
|
||||
data: {
|
||||
resources: profile.resources,
|
||||
lastUpdated: new Date().toISOString(),
|
||||
},
|
||||
correlationId,
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -103,43 +103,43 @@ const getResources = asyncHandler(async (req, res) => {
|
|||
* GET /api/player/stats
|
||||
*/
|
||||
const getStats = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
|
||||
logger.info('Player statistics request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
logger.info('Player statistics request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
});
|
||||
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
|
||||
const detailedStats = {
|
||||
...profile.stats,
|
||||
winRate: profile.stats.totalBattles > 0
|
||||
? Math.round((profile.stats.battlesWon / profile.stats.totalBattles) * 100)
|
||||
: 0,
|
||||
lossRate: profile.stats.totalBattles > 0
|
||||
? Math.round(((profile.stats.totalBattles - profile.stats.battlesWon) / profile.stats.totalBattles) * 100)
|
||||
: 0,
|
||||
accountAge: Math.floor((Date.now() - new Date(profile.createdAt).getTime()) / (1000 * 60 * 60 * 24)) // days
|
||||
};
|
||||
const detailedStats = {
|
||||
...profile.stats,
|
||||
winRate: profile.stats.totalBattles > 0
|
||||
? Math.round((profile.stats.battlesWon / profile.stats.totalBattles) * 100)
|
||||
: 0,
|
||||
lossRate: profile.stats.totalBattles > 0
|
||||
? Math.round(((profile.stats.totalBattles - profile.stats.battlesWon) / profile.stats.totalBattles) * 100)
|
||||
: 0,
|
||||
accountAge: Math.floor((Date.now() - new Date(profile.createdAt).getTime()) / (1000 * 60 * 60 * 24)), // days
|
||||
};
|
||||
|
||||
logger.info('Player statistics retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
totalBattles: detailedStats.totalBattles,
|
||||
winRate: detailedStats.winRate
|
||||
});
|
||||
logger.info('Player statistics retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
totalBattles: detailedStats.totalBattles,
|
||||
winRate: detailedStats.winRate,
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Statistics retrieved successfully',
|
||||
data: {
|
||||
stats: detailedStats,
|
||||
lastUpdated: new Date().toISOString()
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Statistics retrieved successfully',
|
||||
data: {
|
||||
stats: detailedStats,
|
||||
lastUpdated: new Date().toISOString(),
|
||||
},
|
||||
correlationId,
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -147,32 +147,32 @@ const getStats = asyncHandler(async (req, res) => {
|
|||
* PUT /api/player/settings
|
||||
*/
|
||||
const updateSettings = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const settings = req.body;
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const settings = req.body;
|
||||
|
||||
logger.info('Player settings update request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
settingsKeys: Object.keys(settings)
|
||||
});
|
||||
logger.info('Player settings update request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
settingsKeys: Object.keys(settings),
|
||||
});
|
||||
|
||||
// TODO: Implement player settings update
|
||||
// This would involve:
|
||||
// 1. Validate settings data
|
||||
// 2. Update player_settings table
|
||||
// 3. Return updated settings
|
||||
// TODO: Implement player settings update
|
||||
// This would involve:
|
||||
// 1. Validate settings data
|
||||
// 2. Update player_settings table
|
||||
// 3. Return updated settings
|
||||
|
||||
logger.warn('Player settings update requested but not implemented', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
logger.warn('Player settings update requested but not implemented', {
|
||||
correlationId,
|
||||
playerId,
|
||||
});
|
||||
|
||||
res.status(501).json({
|
||||
success: false,
|
||||
message: 'Player settings update feature not yet implemented',
|
||||
correlationId
|
||||
});
|
||||
res.status(501).json({
|
||||
success: false,
|
||||
message: 'Player settings update feature not yet implemented',
|
||||
correlationId,
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -180,49 +180,49 @@ const updateSettings = asyncHandler(async (req, res) => {
|
|||
* GET /api/player/activity
|
||||
*/
|
||||
const getActivity = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { page = 1, limit = 20 } = req.query;
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { page = 1, limit = 20 } = req.query;
|
||||
|
||||
logger.info('Player activity log request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
page,
|
||||
limit
|
||||
});
|
||||
logger.info('Player activity log request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
page,
|
||||
limit,
|
||||
});
|
||||
|
||||
// TODO: Implement player activity log retrieval
|
||||
// This would show recent actions like:
|
||||
// - Colony creations/updates
|
||||
// - Fleet movements
|
||||
// - Research completions
|
||||
// - Battle results
|
||||
// - Resource transactions
|
||||
// TODO: Implement player activity log retrieval
|
||||
// This would show recent actions like:
|
||||
// - Colony creations/updates
|
||||
// - Fleet movements
|
||||
// - Research completions
|
||||
// - Battle results
|
||||
// - Resource transactions
|
||||
|
||||
const mockActivity = {
|
||||
activities: [],
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total: 0,
|
||||
totalPages: 0,
|
||||
hasNext: false,
|
||||
hasPrev: false
|
||||
}
|
||||
};
|
||||
const mockActivity = {
|
||||
activities: [],
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total: 0,
|
||||
totalPages: 0,
|
||||
hasNext: false,
|
||||
hasPrev: false,
|
||||
},
|
||||
};
|
||||
|
||||
logger.info('Player activity log retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
activitiesCount: mockActivity.activities.length
|
||||
});
|
||||
logger.info('Player activity log retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
activitiesCount: mockActivity.activities.length,
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Activity log retrieved successfully',
|
||||
data: mockActivity,
|
||||
correlationId
|
||||
});
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Activity log retrieved successfully',
|
||||
data: mockActivity,
|
||||
correlationId,
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -230,42 +230,42 @@ const getActivity = asyncHandler(async (req, res) => {
|
|||
* GET /api/player/notifications
|
||||
*/
|
||||
const getNotifications = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { unreadOnly = false } = req.query;
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { unreadOnly = false } = req.query;
|
||||
|
||||
logger.info('Player notifications request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
unreadOnly
|
||||
});
|
||||
logger.info('Player notifications request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
unreadOnly,
|
||||
});
|
||||
|
||||
// TODO: Implement player notifications retrieval
|
||||
// This would show:
|
||||
// - System messages
|
||||
// - Battle results
|
||||
// - Research completions
|
||||
// - Fleet arrival notifications
|
||||
// - Player messages
|
||||
// TODO: Implement player notifications retrieval
|
||||
// This would show:
|
||||
// - System messages
|
||||
// - Battle results
|
||||
// - Research completions
|
||||
// - Fleet arrival notifications
|
||||
// - Player messages
|
||||
|
||||
const mockNotifications = {
|
||||
notifications: [],
|
||||
unreadCount: 0,
|
||||
totalCount: 0
|
||||
};
|
||||
const mockNotifications = {
|
||||
notifications: [],
|
||||
unreadCount: 0,
|
||||
totalCount: 0,
|
||||
};
|
||||
|
||||
logger.info('Player notifications retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
unreadCount: mockNotifications.unreadCount
|
||||
});
|
||||
logger.info('Player notifications retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
unreadCount: mockNotifications.unreadCount,
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Notifications retrieved successfully',
|
||||
data: mockNotifications,
|
||||
correlationId
|
||||
});
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Notifications retrieved successfully',
|
||||
data: mockNotifications,
|
||||
correlationId,
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -273,35 +273,35 @@ const getNotifications = asyncHandler(async (req, res) => {
|
|||
* PUT /api/player/notifications/read
|
||||
*/
|
||||
const markNotificationsRead = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { notificationIds } = req.body;
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { notificationIds } = req.body;
|
||||
|
||||
logger.info('Mark notifications read request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
notificationCount: notificationIds?.length || 0
|
||||
});
|
||||
logger.info('Mark notifications read request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
notificationCount: notificationIds?.length || 0,
|
||||
});
|
||||
|
||||
// TODO: Implement notification marking as read
|
||||
logger.warn('Mark notifications read requested but not implemented', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
// TODO: Implement notification marking as read
|
||||
logger.warn('Mark notifications read requested but not implemented', {
|
||||
correlationId,
|
||||
playerId,
|
||||
});
|
||||
|
||||
res.status(501).json({
|
||||
success: false,
|
||||
message: 'Mark notifications read feature not yet implemented',
|
||||
correlationId
|
||||
});
|
||||
res.status(501).json({
|
||||
success: false,
|
||||
message: 'Mark notifications read feature not yet implemented',
|
||||
correlationId,
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
getDashboard,
|
||||
getResources,
|
||||
getStats,
|
||||
updateSettings,
|
||||
getActivity,
|
||||
getNotifications,
|
||||
markNotificationsRead
|
||||
};
|
||||
getDashboard,
|
||||
getResources,
|
||||
getStats,
|
||||
updateSettings,
|
||||
getActivity,
|
||||
getNotifications,
|
||||
markNotificationsRead,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue