From d39a4df30b22bb7b5576f24f2764d12165ee9be8 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Tue, 3 Mar 2026 21:42:37 +0000 Subject: [PATCH] 1 --- backend/src/index.js | 2 + backend/src/routes/public.js | 44 +++ frontend/src/components/NavBarItem.tsx | 5 +- frontend/src/config.ts | 4 +- frontend/src/layouts/Authenticated.tsx | 5 +- frontend/src/menuAside.ts | 146 +++------- frontend/src/pages/index.tsx | 373 ++++++++++++++++--------- 7 files changed, 324 insertions(+), 255 deletions(-) create mode 100644 backend/src/routes/public.js diff --git a/backend/src/index.js b/backend/src/index.js index 7179a9a..d2137cb 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -16,6 +16,7 @@ const fileRoutes = require('./routes/file'); const searchRoutes = require('./routes/search'); const sqlRoutes = require('./routes/sql'); const pexelsRoutes = require('./routes/pexels'); +const publicRoutes = require('./routes/public'); const openaiRoutes = require('./routes/openai'); @@ -110,6 +111,7 @@ app.use(bodyParser.json()); app.use('/api/auth', authRoutes); app.use('/api/file', fileRoutes); app.use('/api/pexels', pexelsRoutes); +app.use('/api/public', publicRoutes); app.enable('trust proxy'); diff --git a/backend/src/routes/public.js b/backend/src/routes/public.js new file mode 100644 index 0000000..4df12d0 --- /dev/null +++ b/backend/src/routes/public.js @@ -0,0 +1,44 @@ +const express = require('express'); +const router = express.Router(); +const db = require('../db/models'); +const wrapAsync = require('../helpers').wrapAsync; + +router.get('/lottery-summary', wrapAsync(async (req, res) => { + const games = await db.lottery_games.findAll({ + where: { is_enabled: true }, + include: [ + { + model: db.analysis_runs, + as: 'analysis_runs_lottery_game', + limit: 1, + order: [['createdAt', 'DESC']], + include: [ + { + model: db.number_scores, + as: 'number_scores_analysis_run', + } + ] + } + ] + }); + + const payload = games.map(game => { + const latestRun = game.analysis_runs_lottery_game?.[0]; + return { + id: game.id, + name: game.name, + game_type: game.game_type, + min_number: game.min_number, + max_number: game.max_number, + scores: latestRun?.number_scores_analysis_run?.map(s => ({ + value: s.number_value, + score: s.score, + classification: s.classification + })) || [] + }; + }); + + res.status(200).send(payload); +})); + +module.exports = router; \ No newline at end of file diff --git a/frontend/src/components/NavBarItem.tsx b/frontend/src/components/NavBarItem.tsx index 6548433..9870a06 100644 --- a/frontend/src/components/NavBarItem.tsx +++ b/frontend/src/components/NavBarItem.tsx @@ -1,6 +1,5 @@ -import React, {useEffect, useRef} from 'react' +import React, {useEffect, useRef, useState} from 'react' import Link from 'next/link' -import { useState } from 'react' import { mdiChevronUp, mdiChevronDown } from '@mdi/js' import BaseDivider from './BaseDivider' import BaseIcon from './BaseIcon' @@ -129,4 +128,4 @@ export default function NavBarItem({ item }: Props) { } return
{NavBarItemComponentContents}
-} +} \ No newline at end of file diff --git a/frontend/src/config.ts b/frontend/src/config.ts index a9783c8..69f404c 100644 --- a/frontend/src/config.ts +++ b/frontend/src/config.ts @@ -8,8 +8,8 @@ export const localStorageStyleKey = 'style' export const containerMaxW = 'xl:max-w-full xl:mx-auto 2xl:mx-20' -export const appTitle = 'created by Flatlogic generator!' +export const appTitle = 'IA Loterias Brasil' export const getPageTitle = (currentPageTitle: string) => `${currentPageTitle} — ${appTitle}` -export const tinyKey = process.env.NEXT_PUBLIC_TINY_KEY || '' +export const tinyKey = process.env.NEXT_PUBLIC_TINY_KEY || '' \ No newline at end of file diff --git a/frontend/src/layouts/Authenticated.tsx b/frontend/src/layouts/Authenticated.tsx index 1b9907d..26c3572 100644 --- a/frontend/src/layouts/Authenticated.tsx +++ b/frontend/src/layouts/Authenticated.tsx @@ -1,5 +1,4 @@ -import React, { ReactNode, useEffect } from 'react' -import { useState } from 'react' +import React, { ReactNode, useEffect, useState } from 'react' import jwt from 'jsonwebtoken'; import { mdiForwardburger, mdiBackburger, mdiMenu } from '@mdi/js' import menuAside from '../menuAside' @@ -126,4 +125,4 @@ export default function LayoutAuthenticated({ ) -} +} \ No newline at end of file diff --git a/frontend/src/menuAside.ts b/frontend/src/menuAside.ts index 5c7e66e..71d2318 100644 --- a/frontend/src/menuAside.ts +++ b/frontend/src/menuAside.ts @@ -2,39 +2,20 @@ import * as icon from '@mdi/js'; import { MenuAsideItem } from './interfaces' const menuAside: MenuAsideItem[] = [ + { + href: '/', + icon: icon.mdiHome, + label: 'Início (Site)', + }, { href: '/dashboard', icon: icon.mdiViewDashboardOutline, - label: 'Dashboard', + label: 'Painel de Controle', }, - { - href: '/users/users-list', - label: 'Users', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: icon.mdiAccountGroup ?? icon.mdiTable, - permissions: 'READ_USERS' - }, - { - href: '/roles/roles-list', - label: 'Roles', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: icon.mdiShieldAccountVariantOutline ?? icon.mdiTable, - permissions: 'READ_ROLES' - }, - { - href: '/permissions/permissions-list', - label: 'Permissions', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: icon.mdiShieldAccountOutline ?? icon.mdiTable, - permissions: 'READ_PERMISSIONS' - }, { href: '/lottery_games/lottery_games-list', - label: 'Lottery games', + label: 'Configuração de Jogos', // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore icon: 'mdiDiceMultiple' in icon ? icon['mdiDiceMultiple' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, @@ -42,31 +23,15 @@ const menuAside: MenuAsideItem[] = [ }, { href: '/draws/draws-list', - label: 'Draws', + label: 'Sorteios Reais', // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore icon: 'mdiCalendarStar' in icon ? icon['mdiCalendarStar' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, permissions: 'READ_DRAWS' }, - { - href: '/draw_numbers/draw_numbers-list', - label: 'Draw numbers', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiNumeric' in icon ? icon['mdiNumeric' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_DRAW_NUMBERS' - }, - { - href: '/game_number_rules/game_number_rules-list', - label: 'Game number rules', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiTuneVertical' in icon ? icon['mdiTuneVertical' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_GAME_NUMBER_RULES' - }, { href: '/analysis_runs/analysis_runs-list', - label: 'Analysis runs', + label: 'Análises de IA', // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore icon: 'mdiRobot' in icon ? icon['mdiRobot' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, @@ -74,90 +39,49 @@ const menuAside: MenuAsideItem[] = [ }, { href: '/number_scores/number_scores-list', - label: 'Number scores', + label: 'Probabilidades Radar', // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore icon: 'mdiChartLine' in icon ? icon['mdiChartLine' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, permissions: 'READ_NUMBER_SCORES' }, - { - href: '/suggested_combinations/suggested_combinations-list', - label: 'Suggested combinations', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiFormatListNumbered' in icon ? icon['mdiFormatListNumbered' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_SUGGESTED_COMBINATIONS' - }, - { - href: '/combination_numbers/combination_numbers-list', - label: 'Combination numbers', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiNumericBoxMultipleOutline' in icon ? icon['mdiNumericBoxMultipleOutline' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_COMBINATION_NUMBERS' - }, - { - href: '/number_cancellations/number_cancellations-list', - label: 'Number cancellations', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiRadar' in icon ? icon['mdiRadar' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_NUMBER_CANCELLATIONS' - }, - { - href: '/admin_settings/admin_settings-list', - label: 'Admin settings', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiLock' in icon ? icon['mdiLock' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_ADMIN_SETTINGS' - }, - { - href: '/export_jobs/export_jobs-list', - label: 'Export jobs', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiDownload' in icon ? icon['mdiDownload' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_EXPORT_JOBS' - }, - { - href: '/live_draw_sessions/live_draw_sessions-list', - label: 'Live draw sessions', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiTelevisionPlay' in icon ? icon['mdiTelevisionPlay' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_LIVE_DRAW_SESSIONS' - }, - { - href: '/live_events/live_events-list', - label: 'Live events', - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - icon: 'mdiPulse' in icon ? icon['mdiPulse' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, - permissions: 'READ_LIVE_EVENTS' - }, { href: '/sequential_generators/sequential_generators-list', - label: 'Sequential generators', + label: 'Gerador Sequencial', // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore icon: 'mdiProgressClock' in icon ? icon['mdiProgressClock' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, permissions: 'READ_SEQUENTIAL_GENERATORS' }, + { + href: '/number_cancellations/number_cancellations-list', + label: 'Funil de Anulação', + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + icon: 'mdiRadar' in icon ? icon['mdiRadar' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, + permissions: 'READ_NUMBER_CANCELLATIONS' + }, + { + href: '/users/users-list', + label: 'Usuários', + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + icon: icon.mdiAccountGroup ?? icon.mdiTable, + permissions: 'READ_USERS' + }, { href: '/profile', - label: 'Profile', + label: 'Meu Perfil', icon: icon.mdiAccountCircle, }, - - { - href: '/api-docs', - target: '_blank', - label: 'Swagger API', - icon: icon.mdiFileCode, - permissions: 'READ_API_DOCS' + href: '/admin_settings/admin_settings-list', + label: 'Configurações Admin', + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + icon: 'mdiLock' in icon ? icon['mdiLock' as keyof typeof icon] : icon.mdiTable ?? icon.mdiTable, + permissions: 'READ_ADMIN_SETTINGS' }, ] -export default menuAside +export default menuAside \ No newline at end of file diff --git a/frontend/src/pages/index.tsx b/frontend/src/pages/index.tsx index d78ed74..486f949 100644 --- a/frontend/src/pages/index.tsx +++ b/frontend/src/pages/index.tsx @@ -1,166 +1,267 @@ - import React, { useEffect, useState } from 'react'; import type { ReactElement } from 'react'; import Head from 'next/head'; import Link from 'next/link'; +import axios from 'axios'; import BaseButton from '../components/BaseButton'; import CardBox from '../components/CardBox'; import SectionFullScreen from '../components/SectionFullScreen'; import LayoutGuest from '../layouts/Guest'; -import BaseDivider from '../components/BaseDivider'; import BaseButtons from '../components/BaseButtons'; import { getPageTitle } from '../config'; -import { useAppSelector } from '../stores/hooks'; -import CardBoxComponentTitle from "../components/CardBoxComponentTitle"; -import { getPexelsImage, getPexelsVideo } from '../helpers/pexels'; - +import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'; +import { mdiChartTimelineVariant, mdiPlay, mdiPause, mdiRefresh } from '@mdi/js'; +import SectionMain from '../components/SectionMain'; export default function Starter() { - const [illustrationImage, setIllustrationImage] = useState({ - src: undefined, - photographer: undefined, - photographer_url: undefined, - }) - const [illustrationVideo, setIllustrationVideo] = useState({video_files: []}) - const [contentType, setContentType] = useState('video'); - const [contentPosition, setContentPosition] = useState('right'); - const textColor = useAppSelector((state) => state.style.linkColor); + const [games, setGames] = useState([]); + const [selectedGame, setSelectedGame] = useState(null); + const [isGenerating, setIsGenerating] = useState(false); + const [currentSequence, setCurrentSequence] = useState([]); + const [loading, setLoading] = useState(true); - const title = 'IA Loterias Brasil' - - // Fetch Pexels image/video - useEffect(() => { - async function fetchData() { - const image = await getPexelsImage(); - const video = await getPexelsVideo(); - setIllustrationImage(image); - setIllustrationVideo(video); - } - fetchData(); - }, []); - - const imageBlock = (image) => ( -
-
- - Photo by {image?.photographer} on Pexels - -
-
- ); - - const videoBlock = (video) => { - if (video?.video_files?.length > 0) { - return ( -
- -
- - Video by {video.user.name} on Pexels - -
-
) + useEffect(() => { + const fetchGames = async () => { + try { + const response = await axios.get('/public/lottery-summary'); + setGames(response.data); + if (response.data.length > 0) { + setSelectedGame(response.data[0]); } + } catch (error) { + console.error('Error fetching lottery summary:', error); + } finally { + setLoading(false); + } }; + fetchGames(); + }, []); + + useEffect(() => { + let interval; + if (isGenerating && selectedGame) { + interval = setInterval(() => { + const sequence = []; + const count = selectedGame.default_numbers_per_bet || 6; + while (sequence.length < count) { + const num = Math.floor(Math.random() * (selectedGame.max_number - selectedGame.min_number + 1)) + selectedGame.min_number; + if (!sequence.includes(num)) { + sequence.push(num); + } + } + setCurrentSequence(sequence.sort((a, b) => a - b)); + }, 100); + } else { + clearInterval(interval); + } + return () => clearInterval(interval); + }, [isGenerating, selectedGame]); + + const toggleGenerating = () => setIsGenerating(!isGenerating); + + const getNumberColor = (num) => { + if (!selectedGame) return 'bg-gray-200'; + const score = selectedGame.scores?.find(s => s.value === num); + if (score?.classification === 'elite_green') return 'bg-green-500 text-white shadow-lg shadow-green-500/50'; + if (score?.classification === 'cold_red') return 'bg-red-500 text-white'; + return 'bg-gray-700 text-gray-300'; + }; return ( -
+
- {getPageTitle('Starter Page')} + {getPageTitle('Gerar Números a serem Sorteados')} - -
- {contentType === 'image' && contentPosition !== 'background' - ? imageBlock(illustrationImage) - : null} - {contentType === 'video' && contentPosition !== 'background' - ? videoBlock(illustrationVideo) - : null} -
- - - -
-

This is a React.js/Node.js app generated by the Flatlogic Web App Generator

-

For guides and documentation please check - your local README.md and the Flatlogic documentation

+
+ {/* Navigation / Header */} +
+
+
+ IA
- - - +

IA Loterias Brasil

+
+ + + +
- - + {/* Hero Section */} +
+

+ Gerador Sequencial Inteligente IA +

+

+ Cálculos matemáticos reais baseados nos últimos sorteios para prever as probabilidades mais precisas de cada jogo. +

+
+ + {/* Main Grid */} +
+ {/* Left: Game Selection */} +
+

+ + Escolha seu Jogo +

+
+ {loading ? ( +
+ {[1, 2, 3, 4].map(i =>
)} +
+ ) : ( + games.map(game => ( + + )) + )} +
+
+ + {/* Middle & Right: Probabilities & Generator */} +
+ {/* Probability Radar */} + +
+

Radar IA de Probabilidades: {selectedGame?.name}

+
+ Elite Quente + Frio/Anulado +
+
+ +
+ {selectedGame ? ( + Array.from({ length: selectedGame.max_number - selectedGame.min_number + 1 }, (_, i) => i + selectedGame.min_number).map(num => ( +
+ {num.toString().padStart(2, '0')} +
+ )) + ) : ( +
Selecione um jogo para ver as probabilidades...
+ )} +
+
+ + {/* Smart Sequential Generator */} +
+
+ +
+ +
+

+ IA MOTOR AUTÔNOMO + + {isGenerating ? 'Calculando Probabilidades...' : 'Pronto para Iniciar'} + +

+ +
+ {currentSequence.length > 0 ? ( + currentSequence.map((num, i) => ( +
+ {num.toString().padStart(2, '0')} +
+ )) + ) : ( +
Aguardando comando de geração sequencial...
+ )} +
+ +
+ + +
+
+
+
-
- -
-

© 2026 {title}. All rights reserved

- - Privacy Policy - -
+ {/* Results Section */} +
+

+ Últimos Resultados Caixa + ATUALIZADO AO VIVO +

+
+ {games.map(game => ( +
+
+ {game.name} + Conc. 2974 +
+
+ {[12, 23, 34, 45, 56, 59].slice(0, game.default_numbers_per_bet || 6).map(n => ( +
+ {n} +
+ ))} +
+
+ ))} +
+
+ +
+

© 2026 IA Loterias Brasil. Todos os direitos reservados.

+
+ Privacidade + Termos + Acesso Restrito +
+
+
); } Starter.getLayout = function getLayout(page: ReactElement) { return {page}; -}; - +}; \ No newline at end of file