diff --git a/backend/src/db/models/game_access_passes.js b/backend/src/db/models/game_access_passes.js index 50305a5..18e7127 100644 --- a/backend/src/db/models/game_access_passes.js +++ b/backend/src/db/models/game_access_passes.js @@ -61,6 +61,10 @@ revoked_reason: { }, +guest_id: { + type: DataTypes.TEXT, +}, + importHash: { type: DataTypes.STRING(255), allowNull: true, @@ -138,6 +142,4 @@ revoked_reason: { return game_access_passes; -}; - - +}; \ No newline at end of file diff --git a/backend/src/db/models/orders.js b/backend/src/db/models/orders.js index 1eb32f6..79b2ba0 100644 --- a/backend/src/db/models/orders.js +++ b/backend/src/db/models/orders.js @@ -84,6 +84,10 @@ expires_at: { }, +guest_id: { + type: DataTypes.TEXT, +}, + importHash: { type: DataTypes.STRING(255), allowNull: true, @@ -177,6 +181,4 @@ expires_at: { return orders; -}; - - +}; \ No newline at end of file diff --git a/backend/src/routes/games.js b/backend/src/routes/games.js index a0e8d59..edf9cc6 100644 --- a/backend/src/routes/games.js +++ b/backend/src/routes/games.js @@ -1,4 +1,3 @@ - const express = require('express'); const GamesService = require('../services/games'); @@ -10,6 +9,18 @@ const router = express.Router(); const { parse } = require('json2csv'); +// Public routes for purchase and verification +router.post('/purchase', wrapAsync(async (req, res) => { + const { gameId, timePassId, guestId } = req.body; + const payload = await GamesService.purchase(gameId, timePassId, guestId, req.currentUser); + res.status(200).send(payload); +})); + +router.get('/verify-access', wrapAsync(async (req, res) => { + const { gameId, guestId } = req.query; + const payload = await GamesService.verifyAccess(gameId, guestId, req.currentUser); + res.status(200).send(payload); +})); const { checkCrudPermissions, @@ -459,4 +470,4 @@ router.get('/:id', wrapAsync(async (req, res) => { router.use('/', require('../helpers').commonErrorHandler); -module.exports = router; +module.exports = router; \ No newline at end of file diff --git a/backend/src/services/games.js b/backend/src/services/games.js index c0cccc7..3acfb09 100644 --- a/backend/src/services/games.js +++ b/backend/src/services/games.js @@ -6,10 +6,7 @@ const csv = require('csv-parser'); const axios = require('axios'); const config = require('../config'); const stream = require('stream'); - - - - +const { Op } = require('sequelize'); module.exports = class GamesService { static async create(data, currentUser) { @@ -132,7 +129,77 @@ module.exports = class GamesService { } } - -}; + static async purchase(gameId, timePassId, guestId, currentUser) { + const transaction = await db.sequelize.transaction(); + try { + const game = await db.games.findByPk(gameId, { transaction }); + const timePass = await db.game_time_passes.findByPk(timePassId, { transaction }); + if (!game || !timePass) { + throw new ValidationError('Game or Time Pass not found'); + } + // Create a simulated order + const order = await db.orders.create({ + status: 'paid', + amount: timePass.price, + currency: 'USD', + userId: currentUser ? currentUser.id : null, + guest_id: guestId, + time_passId: timePassId, + gameId: gameId, + paid_at: new Date(), + }, { transaction }); + + // Calculate access duration + const starts_at = new Date(); + let ends_at = new Date(starts_at); + + if (timePass.duration_days) { + ends_at.setDate(ends_at.getDate() + timePass.duration_days); + } else { + // Default to 1 day if not specified or fallback + ends_at.setDate(ends_at.getDate() + 1); + } + + const accessPass = await db.game_access_passes.create({ + starts_at, + ends_at, + status: 'active', + userId: currentUser ? currentUser.id : null, + guest_id: guestId, + gameId: gameId, + orderId: order.id, + }, { transaction }); + + await transaction.commit(); + return { + success: true, + accessPass, + playUrl: game.web_play_url + }; + } catch (error) { + await transaction.rollback(); + throw error; + } + } + + static async verifyAccess(gameId, guestId, currentUser) { + const where = { + gameId: gameId, + status: 'active', + ends_at: { + [Op.gt]: new Date() + } + }; + + if (currentUser) { + where.userId = currentUser.id; + } else { + where.guest_id = guestId; + } + + const access = await db.game_access_passes.findOne({ where }); + return !!access; + } +}; \ No newline at end of file diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index bfcc808..79d9763 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -11,11 +11,14 @@ import { mdiShieldCheck, mdiChevronRight, mdiBrain, - mdiDeveloperBoard + mdiDeveloperBoard, + mdiLockOutline, + mdiCheckCircle } from '@mdi/js' import BaseIcon from '../components/BaseIcon' import axios from 'axios' import Link from 'next/link' +import { v4 as uuidv4 } from 'uuid' export default function IndexPage() { const [games, setGames] = useState([]) @@ -23,8 +26,20 @@ export default function IndexPage() { const [timePasses, setTimePasses] = useState([]) const [qrCodes, setQrCodes] = useState([]) const [activeCategory, setActiveCategory] = useState('all') + const [selectedGame, setSelectedGame] = useState(null) + const [selectedPass, setSelectedPass] = useState(null) + const [isPurchasing, setIsPurchasing] = useState(false) + const [isUnlocked, setIsUnlocked] = useState(false) + const [guestId, setGuestId] = useState('') useEffect(() => { + let gid = localStorage.getItem('guestId') + if (!gid) { + gid = `guest_${Math.random().toString(36).substring(2, 15)}` + localStorage.setItem('guestId', gid) + } + setGuestId(gid) + const fetchData = async () => { try { const [gamesRes, catsRes, passesRes, qrRes] = await Promise.all([ @@ -44,6 +59,39 @@ export default function IndexPage() { fetchData() }, []) + const checkAccess = async (gameId: string) => { + try { + const res = await axios.get(`/games/verify-access?gameId=${gameId}&guestId=${guestId}`) + setIsUnlocked(res.data) + } catch (err) { + console.error("Failed to verify access", err) + } + } + + useEffect(() => { + if (selectedGame) { + checkAccess(selectedGame.id) + } + }, [selectedGame, guestId]) + + const handlePurchase = async () => { + if (!selectedGame || !selectedPass) return + setIsPurchasing(true) + try { + await axios.post('/games/purchase', { + gameId: selectedGame.id, + timePassId: selectedPass.id, + guestId: guestId + }) + setIsUnlocked(true) + // Scroll to game area if needed + } catch (err) { + console.error("Purchase failed", err) + } finally { + setIsPurchasing(false) + } + } + const filteredGames = activeCategory === 'all' ? games : games.filter((g: any) => g.game_categoryId === activeCategory) @@ -51,7 +99,7 @@ export default function IndexPage() { return (
- {getPageTitle('Advanced Gaming & AI Dev Platform')} + {getPageTitle('Nexus Gaming - Premium AI Game Platform')} {/* Navbar */} @@ -82,66 +130,18 @@ export default function IndexPage() {
- Next-Gen Game Distribution Platform + Intelligent Game Development & Distribution

- PLAY THE FUTURE
- OF GAMING. + REDEFINING PLAY
+ WITH AI.

- Instant access to premium high-fidelity games. Powered by AI development tools and decentralized payment systems. + Instant access to 2D and 3D premium games. Create your own gaming world with our advanced Developer AI.

- - -
-
- - - {/* AI Developer Teaser */} -
-
-
-
-
- -
-

World's Most Advanced AI Game Creator

-

- Transform your ideas into high-quality game projects instantly. Our Intelligent Developer AI architects mechanics, design docs, and technical structures for 2D and 3D experiences. -

-
-
- -
-

Rapid Prototyping

-

From concept to GDD in seconds.

-
-
-
- -
-

Multi-Platform

-

Optimized for all modern engines.

-
-
-
- -
-
-
-
-
-
- -
NEURAL_NET: ACTIVE
-
-
-
-
-
-
-
+ +
@@ -150,8 +150,8 @@ export default function IndexPage() {
-

Game Gallery

-

The most curated selection of high-end experiences.

+

Curated Gallery

+

Unlock premium experiences with instant QR payments.

- {/* Payment & QR Section */} -
-
-
-

Instant Access

-

Choose your duration and unlock the experience via secure QR payment.

-
- -
- {/* Time Passes */} -
- {timePasses.map((pass: any) => ( -
-
+ {/* Integrated Selection & Payment */} + {selectedGame && ( +
+
+
-
{pass.duration_minutes} MIN
-
Full Access Pass
-
-
${pass.price}
-
-
- ))} -
- - {/* QR Payment UI */} -
-
-
-

Scan & Play

-

- Select your preferred payment method. Access is granted automatically upon network confirmation. -

-
-
- - Encrypted Transaction -
-
- - Instant Activation -
-
-
-
-
- {qrCodes.slice(0, 2).map((qr: any) => ( -
-
- {qr.payment_method} +
+
+ +
+
+

{selectedGame.title}

+

{selectedGame.short_description}

+
- {qr.payment_method} -
- ))} -
-
-
WAITING FOR PAYMENT...
-
Transaction ID: 0x{Math.random().toString(16).slice(2, 10).toUpperCase()}
-
+ + {isUnlocked ? ( +
+
+ +
+

Access Granted!

+

You have an active pass for this game. Ready to play?

+ window.open(selectedGame.web_play_url, '_blank')} + /> +
+ ) : ( +
+

+ + Choose Your Access Time +

+
+ {timePasses.map((pass: any) => ( +
setSelectedPass(pass)} + className={`p-6 rounded-2xl border cursor-pointer transition-all ${selectedPass?.id === pass.id ? 'bg-violet-600 border-violet-400 shadow-lg shadow-violet-500/20' : 'bg-white/5 border-white/5 hover:bg-white/10'}`} + > +
{pass.duration_days ? `${pass.duration_days} DAYS` : `${pass.duration_minutes} MIN`}
+
Full Access
+
${pass.price}
+
+ ))} +
+
+
+ + Encrypted Checkout +
+
ID: {guestId.slice(0, 8)}...
+
+
+ )} +
+ + {!isUnlocked && ( +
+
+
+

Scan to Unlock

+

Select payment method below to generate QR

+
+ +
+ {qrCodes.map((qr: any) => ( +
+
+ {qr.payment_method} +
+ {qr.payment_method} +
+ ))} +
+ +
+
+
+
+ SYNCHRONIZING WITH BLOCKCHAIN... +
+
+ + + +

+ Access is granted automatically after network confirmation. No registration required. +

+
+
+
+ )} +
+
+
+ )} + + {/* AI Studio Teaser */} +
+
+
+
+
+ +
+

Intelligent Developer AI

+

+ Our advanced neural engine can generate complete game architectures. From 2D platforms to 3D shooters, the AI builds everything. +

+
+
+

2D ENGINE

+

Optimized physics and sprite management.

+
+
+

3D CORE

+

Advanced lighting and spatial mechanics.

+ +
+
+
+
+ +
+
+
AI_PROCESSING_SEQUENCE
+
+
+
+
+
+
+
+
+
+
+
{/* Footer */} -
)