From 48d00e12dbbbdcafd56cae502520a682d0c4bfc1 Mon Sep 17 00:00:00 2001 From: shivam <141029609+js-1608@users.noreply.github.com> Date: Thu, 20 Mar 2025 23:06:10 +0530 Subject: [PATCH] updated user view --- package-lock.json | 30 ++ package.json | 2 + public/add.png | Bin 0 -> 4087 bytes public/logo.PNG | Bin 0 -> 37815 bytes src/App.js | 474 +++++++++++++++------------ src/pages/GameList.js | 640 ++++++++++++++++++++++++++++++++++++ src/pages/Home2.js | 483 ++++++++++++--------------- src/pages/Home3.js | 682 +++++++++++++++++++++++++++++++++++++++ src/pages/Today.js | 282 ++++++++++++++++ src/pages/TodaysMatch.js | 298 +++++++++++++++++ 10 files changed, 2408 insertions(+), 483 deletions(-) create mode 100644 public/add.png create mode 100644 public/logo.PNG create mode 100644 src/pages/GameList.js create mode 100644 src/pages/Home3.js create mode 100644 src/pages/Today.js create mode 100644 src/pages/TodaysMatch.js diff --git a/package-lock.json b/package-lock.json index 58e160f..ce7bcfd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,13 @@ "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.8.3", + "chart.js": "^4.4.8", "cors": "^2.8.5", "http": "^0.0.1-security", "jsonwebtoken": "^9.0.2", "lucide-react": "^0.479.0", "react": "^19.0.0", + "react-chartjs-2": "^5.3.0", "react-dom": "^19.0.0", "react-router-dom": "^7.3.0", "react-scripts": "5.0.1", @@ -2785,6 +2787,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", + "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "license": "MIT" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", @@ -5348,6 +5356,18 @@ "node": ">=10" } }, + "node_modules/chart.js": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.8.tgz", + "integrity": "sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/check-types": { "version": "11.2.3", "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", @@ -13463,6 +13483,16 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "node_modules/react-chartjs-2": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz", + "integrity": "sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==", + "license": "MIT", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", diff --git a/package.json b/package.json index a96ff1d..001f408 100644 --- a/package.json +++ b/package.json @@ -8,11 +8,13 @@ "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^13.5.0", "axios": "^1.8.3", + "chart.js": "^4.4.8", "cors": "^2.8.5", "http": "^0.0.1-security", "jsonwebtoken": "^9.0.2", "lucide-react": "^0.479.0", "react": "^19.0.0", + "react-chartjs-2": "^5.3.0", "react-dom": "^19.0.0", "react-router-dom": "^7.3.0", "react-scripts": "5.0.1", diff --git a/public/add.png b/public/add.png new file mode 100644 index 0000000000000000000000000000000000000000..b5d89d86f833a5c657bd433e9974e011826850e5 GIT binary patch literal 4087 zcmVu(Gszeu4Y9 z0GytosjIEp+uYLA)Q*vqFn#kpg7nPI&SGY3H-Pl@_4T;9yYBAqQvp>G1w?c6w@Va+Q~w*5drc*847j{U&+yYn=A{&0cz?_fCxU{MUo< z_5Qlg`X8rOTD5VLwfM}}>i_@uWsuzF*RQOehj)<2{_@xS#XSAyv{s7VjF`E@sd)U= zeqopO{`Tbl>%!c!PW|7WhL*hXxgY$|aH*k~{KrGdt8Z$L)8e#2(XL{=r-A+8qv*O6 z$F?Q4voWW#HIcA8RjNyAtVdO*IH%5-e8P;W*0Xu7L*w%2M6O_)tQV2Xp47)^Relao8QcRdS@04MhkM+|o#Si7E#M&-ud=wL6v!Dw_-bFy39 z{$R8x;PBvN*K@koco6AFh|`aEJ*#Vs8>cBgFh=)xJ+Etv6Dc8>lAF7p*)_#SBRL_M z675TNg1c!S5@OeLyO#KMhRvc8m$qBm$N6t^RAle;qg~JM`r)^kUWDL4$6MRRvrlpv z**m?n>lt1*-1}Xg(ZWjd!LDa`&G4x6K`tRU0=}{9IbJV3Zv3i%k-bA*bKD}HbgIRS z+}ialuM?`(Vn+5(bqi~2_^?wgwpx1!cXvI{YlCN{0dEP9s}#jn3sa)YTU)>v9ZHCj+0qg47I4lqq}q6yU)W;M z<*m)*(+;PktDqzYPj@}v_a4tUA()b)(iVYk@NOFSsu3gqR0y|9HF*90pzlvFeeUli zo<}NzDamak2DoU0x8GeN+r&Wj(L}RSh-w^-KdC6mMIvCUW!R3v0U)aPH}_r$YRGXQ zy24fJ7aft3KdU%*^#*Uvfrbcxh8tb38hJr@bs0IYifFu4U_?0r_S&|Qh66UKCS@71 zCbimRQgqi~Qk%G?=B0|ys!2-zqF}ca8@xUQ0S7ih4nijX8x_9u@+iwl6F~@3(Oy|0 zXdjiEm>M2+l8oR8Si!lE9w-dnM{NBeSh>WZd;LipQBF{Ab8o3EBMUM!uqwE#>lmP3 zZenWqJVi*g@mCe+eo*|DeKW98afR^f_`j&Nxp!2S5ua_JqL5(Ij66xJ2&Uw3DiLtu z0}R%fzC|&g3fXf`@-MCRk9%m9#ZTv$;Ne;8iTOQ5Tf%;^; z!DQB(3_RJjezP}gHGSEosoR>hTtO1*ftZBiRjJm*gVOOm!}UHqPfA2ij(;4mq6}HooLQG;Sp~zS~ANzGS2N zv@%@I=Svd0CKwsCZ8|g-&wl+-HzruvOuP(Ep-i04+i*A)8EGz%jW3vJQ4lh#Az9E$ zFtTO@Orv`{SN|hSgG`>)A?w19Z=tAg3>~4O zJ(RMw-Eag4hw`(Kk?GtHU*23umHT4&Fi%C+Ztzk!VyaEEA1xYvd(e-r9hpLn5_Pl0 zoH0-D;*3lUM-b1dT9E;|eBxjcztpC+Yv4HK)zGZQ8JW@=9e|Kt0M6Q`>sdY_RmBK6 ztHC>`n^O2!f6*4PVAYkN`US9A2$nCRu{jHBly*o-Q1!sqV7Tf@Ml1ucq0OMi ziTsKTBpC_Va&7UhBZt05z1JI#@m)^a2pCxcGVrifYYoZRB8_E`8Tp1vvQ~qaR#3z^ za)5vcNUM4tTWWLOa^2RF1q57hX0tW#Hr?9LWNR9jY>RPV$HdZ%u(E-Qp z4F)c!Nq0VEOTyH^Tm=@0*^j^;t=M7*j-`fVj09za;GPzFeJIQSNHXGZzrP}@&aX_# z2q<)i-V*S6Q_mBI01LEiuIWi$780^vgLjd(T5?9%s)Nu9vw|_AZ;v`7J6c1!<=L7t zF&K)m#ZNFo>+6vT8qz-{iOM8iJn5UUl!WkZ$HEB@@_7^DB17e`-Gcj~SVb`ID=0}u zgLjzr>;uvf;xOWSO$f@G#7;osV(111@%9kaJcs<&bz-}}!p9LAq4JQo0{WES=*1=xt@`bg(u#G-N|WP6paa$({F&tk23IRU^m4?HPEz8L59 z-lt_F;QVU*5eQ5?V?l<&QAnB+=y;2UrGjgS4@0IY~zNQUlXy zWhV{E2Cl=8qbMc;7jrVIqhpGxlM-0k%(IIqv`RetX*RNl_%pm0@zx!6%25*p_ zNi#CKP&5OusEZa%6OCg{{)^yPLx)a(5iQzL%Cobx3;-SF7Cfo{nYhgeZjWan^qKry; zOWxr10S|W|BHh>MBz7#Dr$MUW*zImN=*l_VP`iv$b3B~Y0ZY5Xjk#dAnu~6CVFtq{ ztMN=8n9J2{XfV*}`LFhis* zFzh86*@cfe$nh?dkp2CyIU`Zz8$v-xvOmLSGLAp>=Ae1H*w=zEG;fX=*ZYgu!GnZf z?ga%zVwb#nn2!igz4e!7raV1Y;Uv{2c_BJ`;b14?4l-8IE%3lcAv9lTO{6ETE0A!*;s()E^pH*hb@YozUwo$rGpcyvghj zWu#B4{=H}zw+^!8E4>+p%-l@7_(HHZrYnGKXd+|gk@qs2g)JAHubX(@Xj%3FB`Zfo zA|*MONUD^#avyWIru}~3pXS(F%f~llTqnXAiJpfq(Vb5`y`9mo$dOlr@4Bup`M>24 zTz8G3-{vyHJW1z;Oj0ER-tp%F)25}r(n;&5_sAJO}GZ*zsIWx6oS5`Q(e99+AnxyflM(rH6g7Ca8f#U=$4(ri{PfT-3E$@%t^Z_1z8pnI z9Jl`|r-LJ#J>)c=UCoc}`XQf@{}##TH+XmQ`Hfb;*=%0ggMeE{zH9$qcI3;Ed&F_8 z!SDNmyfVu1x5e_g5%B1$WdpwiHL;lrPP`1xHqdF$ln{ku=^-oK&km4=3fhK7cQhK7cQhK7cQhK7cQ phK7cQhK7cQhK7cQhK9y2@PC69FcQG+l6U|B002ovPDHLkV1f^W{GtE= literal 0 HcmV?d00001 diff --git a/public/logo.PNG b/public/logo.PNG new file mode 100644 index 0000000000000000000000000000000000000000..52a28a55758c4b12d587bf17cf78340885286222 GIT binary patch literal 37815 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 { const [token, setToken] = useState(localStorage.getItem('token')); - + const login = (newToken) => { localStorage.setItem('token', newToken); setToken(newToken); }; - + const logout = () => { localStorage.removeItem('token'); setToken(null); }; - + return ( {children} @@ -38,26 +40,26 @@ const apiService = { headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ accessKey, password }) }); - + if (!response.ok) { throw new Error('Login failed'); } - + return response.json(); }, - + getTeams: async (token) => { const response = await fetch(`${API_URL}/api/teams`, { headers: token ? { 'Authorization': `Bearer ${token}` } : {} }); - + if (!response.ok) { throw new Error('Failed to fetch teams'); } - + return response.json(); }, - + createTeam: async (teamData, token) => { const response = await fetch(`${API_URL}/admin/teams`, { method: 'POST', @@ -67,14 +69,14 @@ const apiService = { }, body: JSON.stringify(teamData) }); - + if (!response.ok) { throw new Error('Failed to create team'); } - + return response.json(); }, - + updateTeam: async (id, teamData, token) => { const response = await fetch(`${API_URL}/admin/teams/${id}`, { method: 'PUT', @@ -84,31 +86,31 @@ const apiService = { }, body: JSON.stringify(teamData) }); - + if (!response.ok) { throw new Error('Failed to update team'); } - + return response.json(); }, - + deleteTeam: async (id, token) => { const response = await fetch(`${API_URL}/admin/teams/${id}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); - + if (!response.ok) { throw new Error('Failed to delete team'); } - + return response.json(); }, - + publishResult: async (resultData, token) => { console.log("Publishing result with data:", resultData); console.log("Using token:", token); - + const response = await fetch(`${API_URL}/admin/results`, { method: 'POST', headers: { @@ -118,99 +120,119 @@ const apiService = { body: JSON.stringify(resultData) }); // In your publishResult function - + if (!response.ok) { const errorData = await response.json().catch(() => ({})); console.error("Server responded with error:", response.status, errorData); console.log("Sending exact payload:", JSON.stringify(resultData)); - throw new Error(`Failed to publish result: ${response.status}`); - }else{ + throw new Error(`Failed to publish result: ${response.status}`); + } else { console.log("Response is ok") } - + return response.json(); }, - + updateResult: async (id, resultData, token) => { - const response = await fetch(`${API_URL}/admin/results/${id}`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${token}` - }, - body: JSON.stringify(resultData) - }); - - if (!response.ok) { - throw new Error('Failed to update result'); + console.log(`Updating result ${id} with data:`, resultData); + + try { + const response = await fetch(`${API_URL}/admin/results/${id}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify(resultData) + }); + + if (!response.ok) { + // Try to get error details if available + const errorText = await response.text(); + console.error("Server error response:", errorText); + throw new Error(`Server responded with status: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error("Error in updateResult:", error); + throw error; } - - return response.json(); }, - + deleteResult: async (id, token) => { - const response = await fetch(`${API_URL}/admin/results/${id}`, { - method: 'DELETE', - headers: { 'Authorization': `Bearer ${token}` } - }); - - if (!response.ok) { - throw new Error('Failed to delete result'); + console.log(`Deleting result ${id}`); + + try { + const response = await fetch(`${API_URL}/admin/results/${id}`, { + method: 'DELETE', + headers: { 'Authorization': `Bearer ${token}` } + }); + + if (!response.ok) { + // Try to get error details if available + const errorText = await response.text(); + console.error("Server error response:", errorText); + throw new Error(`Server responded with status: ${response.status}`); + } + + return await response.json(); + } catch (error) { + console.error("Error in deleteResult:", error); + throw error; } - - return response.json(); }, - + getDailyResults: async (date, token) => { const response = await fetch(`${API_URL}/api/results/daily?date=${date}`, { headers: token ? { 'Authorization': `Bearer ${token}` } : {} }); - + if (!response.ok) { throw new Error('Failed to fetch daily results'); } - + return response.json(); }, - + getMonthlyResults: async (team, month) => { const response = await fetch(`${API_URL}/api/results/monthly`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ team, month }) }); - + if (!response.ok) { throw new Error('Failed to fetch monthly results'); } - + return response.json(); }, - + getTodayResults: async () => { const response = await fetch(`${API_URL}/api/today`); - + if (!response.ok) { throw new Error('Failed to fetch today\'s results'); } - + return response.json(); }, - + // Scheduled games API endpoints getScheduledGames: async (date, token) => { const response = await fetch(`${API_URL}/api/schedule?date=${date}`, { headers: token ? { 'Authorization': `Bearer ${token}` } : {} }); - + if (!response.ok) { throw new Error('Failed to fetch scheduled games'); } - + return response.json(); }, - + createScheduledGame: async (gameData, token) => { const response = await fetch(`${API_URL}/admin/schedule`, { method: 'POST', @@ -220,14 +242,14 @@ const apiService = { }, body: JSON.stringify(gameData) }); - + if (!response.ok) { throw new Error('Failed to create scheduled game'); } - + return response.json(); }, - + updateScheduledGame: async (id, gameData, token) => { const response = await fetch(`${API_URL}/admin/schedule/${id}`, { method: 'PUT', @@ -237,24 +259,24 @@ const apiService = { }, body: JSON.stringify(gameData) }); - + if (!response.ok) { throw new Error('Failed to update scheduled game'); } - + return response.json(); }, - + deleteScheduledGame: async (id, token) => { const response = await fetch(`${API_URL}/admin/schedule/${id}`, { method: 'DELETE', headers: { 'Authorization': `Bearer ${token}` } }); - + if (!response.ok) { throw new Error('Failed to delete scheduled game'); } - + return response.json(); } }; @@ -266,7 +288,7 @@ const Login = () => { const [error, setError] = useState(''); const { login } = React.useContext(AuthContext); const navigate = useNavigate(); - + const handleSubmit = async (e) => { e.preventDefault(); try { @@ -279,7 +301,7 @@ const Login = () => { setError('Invalid credentials'); } }; - + return (

Admin Login

@@ -287,18 +309,18 @@ const Login = () => {
- setAccessKey(e.target.value)} required />
- setPassword(e.target.value)} required /> @@ -314,23 +336,23 @@ const TeamList = () => { const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const { token } = React.useContext(AuthContext); - + useEffect(() => { const fetchTeams = async () => { try { const data = await apiService.getTeams(token); setTeams(data); - // alert(teams) + alert(teams) setLoading(false); } catch (err) { setError('Failed to fetch teams'); setLoading(false); } }; - + fetchTeams(); }, [token]); - + const handleDelete = async (id) => { if (window.confirm('Are you sure you want to delete this team?')) { try { @@ -341,10 +363,10 @@ const TeamList = () => { } } }; - + if (loading) return
Loading...
; if (error) return
{error}
; - + return (

Team Management

@@ -364,8 +386,8 @@ const TeamList = () => { {team.name} Edit -
); }; - // Scheduled Games Components const ScheduleCalendar = () => { const [date, setDate] = useState(new Date().toISOString().split('T')[0]); @@ -698,7 +743,7 @@ const ScheduleCalendar = () => { const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const { token } = React.useContext(AuthContext); - + useEffect(() => { const fetchScheduledGames = async () => { try { @@ -710,14 +755,14 @@ const ScheduleCalendar = () => { setLoading(false); } }; - + fetchScheduledGames(); }, [date, token]); - + const handleDateChange = (e) => { setDate(e.target.value); }; - + const handleDeleteScheduledGame = async (id) => { if (window.confirm('Are you sure you want to delete this scheduled game?')) { try { @@ -728,26 +773,26 @@ const ScheduleCalendar = () => { } } }; - + if (loading) return
Loading...
; if (error) return
{error}
; - + return (

Scheduled Games

-
- +

Games scheduled for {date}

Schedule New Game - + {scheduledGames.length === 0 ? (

No games scheduled for this date.

) : ( @@ -770,8 +815,8 @@ const ScheduleCalendar = () => { {game.status} Edit - - + - +
} /> @@ -978,36 +1035,37 @@ const Dashboard = () => { // Protected Route const ProtectedRoute = ({ children }) => { const { isAuthenticated } = React.useContext(AuthContext); - + if (!isAuthenticated) { return ; } - + return children; }; // App const App = () => { return ( - - - - } /> - - - - } - /> - } /> - } /> - - - + + + + } /> + + + + } + /> + } /> + } /> + } /> + + + - ); + ); }; export default App; \ No newline at end of file diff --git a/src/pages/GameList.js b/src/pages/GameList.js new file mode 100644 index 0000000..9a46dd2 --- /dev/null +++ b/src/pages/GameList.js @@ -0,0 +1,640 @@ +import React, { useState, useEffect } from 'react'; +import { BarChart2, Calendar, RefreshCw, Clock, ChevronLeft, ChevronRight } from 'lucide-react'; +import axios from 'axios'; +import TodaysMatch from './TodaysMatch'; +import Today from './Today'; + +const GameList = () => { + const [teams, setTeams] = useState([]); + const [dates, setDates] = useState([]); + const [selectedTeam, setSelectedTeam] = useState(null); + const [showChartView, setShowChartView] = useState(false); + const [showCalendar, setShowCalendar] = useState(false); + const [currentTime, setCurrentTime] = useState(""); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [calendarData, setCalendarData] = useState([]); + const [currentMonth, setCurrentMonth] = useState(new Date()); + const [upcomingMatches, setUpcomingMatches] = useState([]); + + // API URL + const API_URL = 'http://localhost:5500/api'; + + // Format time + const formatTime = (timeString) => { + try { + const date = new Date(timeString); + return date.toLocaleTimeString("en-US", { hour: '2-digit', minute: '2-digit', hour12: true }); + } catch (e) { + return "XX:XX"; + } + }; + + // Check if a match is upcoming + const isUpcoming = (resultTime) => { + try { + const now = new Date(); + const matchTime = new Date(resultTime); + return matchTime > now; + } catch (e) { + return false; + } + }; + + // Fetch teams data + useEffect(() => { + const fetchData = async () => { + try { + setLoading(true); + + // Get all teams + const teamsResponse = await axios.get(`${API_URL}/teams`); + + // Get today's date and format it + const today = new Date(); + const todayFormatted = today.toISOString().split('T')[0]; + + // Get yesterday's date and format it + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + const yesterdayFormatted = yesterday.toISOString().split('T')[0]; + + // Set dates for display + setDates([yesterdayFormatted, todayFormatted]); + + // Get today's results + const todayResultsResponse = await axios.get(`${API_URL}/results/daily?date=${todayFormatted}`); + const todayResults = todayResultsResponse.data; + + // Get yesterday's results + const yesterdayResultsResponse = await axios.get(`${API_URL}/results/daily?date=${yesterdayFormatted}`); + const yesterdayResults = yesterdayResultsResponse.data; + + // Process upcoming matches + const upcoming = todayResults.filter(result => isUpcoming(result.result_time)); + setUpcomingMatches(upcoming); + + // Combine team data with results + const teamsWithResults = teamsResponse.data.map(team => { + // Get all results for this team + const yesterdayTeamResults = yesterdayResults.filter(r => r.team === team.name); + const todayTeamResults = todayResults.filter(r => r.team === team.name); + + // Create result arrays for both days + const yesterdayResultsArr = yesterdayTeamResults.map(r => ({ + result: r.visible_result, + time: formatTime(r.result_time) + })); + + const todayResultsArr = todayTeamResults + .filter(r => !isUpcoming(r.result_time)) + .map(r => ({ + result: r.visible_result, + time: formatTime(r.result_time) + })); + + // Extract latest scheduled time + let latestTime = "XX:XX"; + const latestTodayResult = todayTeamResults + .sort((a, b) => new Date(b.result_time) - new Date(a.result_time)) + .find(r => r.result_time); + + if (latestTodayResult) { + latestTime = formatTime(latestTodayResult.result_time); + } + + return { + id: team.id, + name: team.name, + time: latestTime, + results: { + [yesterdayFormatted]: yesterdayResultsArr, + [todayFormatted]: todayResultsArr + } + }; + }); + + setTeams(teamsWithResults); + setLoading(false); + } catch (err) { + console.error("Error fetching data:", err); + setError("Failed to load team data. Please try again later."); + setLoading(false); + } + }; + + fetchData(); + + // Update current time every minute + const interval = setInterval(() => { + const now = new Date(); + const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" }); + setCurrentTime(formattedTime); + }, 60000); + + // Set initial time + const now = new Date(); + const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" }); + setCurrentTime(formattedTime); + + return () => clearInterval(interval); + }, []); + + // Show chart for selected team + const handleViewChart = async (team) => { + try { + setLoading(true); + // Get monthly results for the selected team + const currentDate = new Date(); + const month = currentDate.getMonth() + 1; + const year = currentDate.getFullYear(); + + const response = await axios.post(`${API_URL}/results/monthly`, { + team: team.name, + month: `${year}-${month.toString().padStart(2, '0')}` + }); + + setSelectedTeam({ + ...team, + chartData: response.data + }); + + setShowChartView(true); + setShowCalendar(false); + setLoading(false); + } catch (err) { + console.error("Error fetching chart data:", err); + setError("Failed to load chart data. Please try again later."); + setLoading(false); + } + }; + + // Load calendar data + const loadCalendarData = async (year, month) => { + try { + setLoading(true); + + // Calculate first and last day of month + const firstDay = new Date(year, month, 1).toISOString().split('T')[0]; + const lastDay = new Date(year, month + 1, 0).toISOString().split('T')[0]; + + // Get results for each day in the month + const dailyResultsPromises = []; + const currentDate = new Date(year, month, 1); + const lastDate = new Date(year, month + 1, 0); + + while (currentDate <= lastDate) { + const dateString = currentDate.toISOString().split('T')[0]; + dailyResultsPromises.push( + axios.get(`${API_URL}/results/daily?date=${dateString}`) + .then(response => ({ + date: dateString, + results: response.data + })) + .catch(() => ({ + date: dateString, + results: [] + })) + ); + currentDate.setDate(currentDate.getDate() + 1); + } + + const allResults = await Promise.all(dailyResultsPromises); + + // Format calendar data + const calendarDays = []; + const firstDayOfMonth = new Date(year, month, 1); + const firstDayWeekday = firstDayOfMonth.getDay(); + + // Add empty cells for days before the first of the month + for (let i = 0; i < firstDayWeekday; i++) { + calendarDays.push(null); + } + + // Add days with results + for (let i = 1; i <= lastDate.getDate(); i++) { + const dateObj = new Date(year, month, i); + const dateStr = dateObj.toISOString().split('T')[0]; + + const dayData = allResults.find(r => r.date === dateStr); + let dayResults = []; + + if (dayData && dayData.results.length > 0) { + // Group by team + const teamResults = {}; + + dayData.results.forEach(result => { + if (!teamResults[result.team]) { + teamResults[result.team] = []; + } + teamResults[result.team].push({ + result: result.visible_result, + time: formatTime(result.result_time) + }); + }); + + // Create an array for display + dayResults = Object.entries(teamResults).map(([team, results]) => ({ + team, + results + })); + } + + calendarDays.push({ + day: i, + date: dateStr, + results: dayResults + }); + } + + setCalendarData(calendarDays); + setLoading(false); + } catch (err) { + console.error("Error loading calendar data:", err); + setError("Failed to load calendar data. Please try again later."); + setLoading(false); + } + }; + + // Handle calendar view button click + const handleCalendarView = () => { + const now = new Date(); + setCurrentMonth(now); + loadCalendarData(now.getFullYear(), now.getMonth()); + setShowCalendar(true); + setShowChartView(false); + }; + + // Handle month change in calendar + const handleMonthChange = (increment) => { + const newMonth = new Date(currentMonth); + newMonth.setMonth(newMonth.getMonth() + increment); + setCurrentMonth(newMonth); + loadCalendarData(newMonth.getFullYear(), newMonth.getMonth()); + }; + + // Refresh data + const handleRefresh = () => { + window.location.reload(); + }; + + // Format date for display + const formatDate = (dateString) => { + return new Date(dateString).toLocaleDateString('en-US', { + weekday: 'short', + month: 'long', + day: 'numeric', + year: 'numeric' + }); + }; + + + const [openIndex, setOpenIndex] = useState(null); + + const toggleFAQ = (index) => { + setOpenIndex(openIndex === index ? null : index); + }; + + const faqs = [ + { question: "HOW TO PLAY", answer: "Details about how to play." }, + { question: "WHERE TO PLAY", answer: "Information on where to play." }, + { question: "WINNING NUMBERS EMAIL", answer: "Sign up for emails." }, + ]; + + return ( +
+ + +
+ {error && ( +
+

{error}

+
+ )} + + +
+ Satta Result of {dates.length > 1 && formatDate(dates[1])} & {dates.length > 0 && formatDate(dates[0])} +
+ + {/* Controls */} +
+
Latest Results
+ +
+ + +
+
+ + {/* Loading indicator */} + {loading && ( +
+
+ + Loading data... +
+
+ )} + + {/* Upcoming Matches */} + {!loading && upcomingMatches.length > 0 && !showChartView && !showCalendar && ( +
+

+ + Upcoming Matches Today +

+
+ + + + + + + + + {upcomingMatches.map((match, index) => ( + + + + + ))} + +
TeamScheduled Time
{match.team}{formatTime(match.result_time)}
+
+
+ )} + + {/* Chart View */} + {!loading && showChartView && selectedTeam && ( +
+

Monthly Chart: {selectedTeam.name}

+
+ + + + + + + + + + {selectedTeam.chartData && selectedTeam.chartData.map((item, index) => ( + + + + + + ))} + {(!selectedTeam.chartData || selectedTeam.chartData.length === 0) && ( + + + + )} + +
DateTimeResult
{new Date(item.result_date).toLocaleDateString()}{formatTime(item.result_time)}{item.result}
No chart data available
+
+
+ +
+
+ )} + + {/* Calendar View - Improved Responsive Design */} + {!loading && showCalendar && ( +
+
+ + +

+ {currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })} +

+ + +
+ +
+ {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => ( +
{day}
+ ))} +
+ +
+ {calendarData.map((day, index) => ( +
+ {day && ( + <> +
+ {day.day} +
+
+ {day.results.length > 0 ? ( + day.results.map((teamResult, i) => ( +
+
{teamResult.team}
+ {teamResult.results.map((r, j) => ( +
+ {r.time} + {r.result} +
+ ))} +
+ )) + ) : ( +
No results
+ )} +
+ + )} +
+ ))} +
+ +
+ +
+
+ )} + + {/* Teams Table with multiple results support */} + {!loading && !showCalendar && !showChartView && ( +
+ + + + + + + + + + + {teams.map(team => ( + + + + + + + + + + ))} + {teams.length === 0 && ( + + + + )} + +
Games List + {dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 0 && new Date(dates[0]).getDate()}th + + {dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 1 && new Date(dates[1]).getDate()}th + Chart
+
{team.name}
+
at {team.time}
+
handleViewChart(team)}>Record Chart
+
+ {dates.length > 0 && team.results[dates[0]] && team.results[dates[0]].length > 0 ? ( +
+ {team.results[dates[0]].map((result, idx) => ( +
+ {result.result} + {result.time} +
+ ))} +
+ ) : ( + XX + )} +
+ {dates.length > 1 && team.results[dates[1]] && team.results[dates[1]].length > 0 ? ( +
+ {team.results[dates[1]].map((result, idx) => ( +
+ {result.result} + {result.time} +
+ ))} +
+ ) : ( + XX + )} +
+
+ +
+
No teams found
+ +
+ +
+
+ )} +
+ +
+ {/* FAQ Section */} +
+ {faqs.map((faq, index) => ( +
+ + {openIndex === index && ( +
+ {faq.answer} +
+ )} +
+ ))} +
+ + {/* Footer Section */} +
+
+

+ MATKA SATTA +

+

+ The Multi-State Lottery Association makes every effort to ensure the + accuracy of winning numbers and other information. Official winning + numbers are those selected in the respective drawings and recorded + under the observation of an independent accounting firm. +

+

+ In the event of a discrepancy, the official drawing results shall + prevail. All winning tickets must be redeemed in the + state/jurisdiction in which they are sold. +

+

+ Media Center + Legal + Privacy + español +

+
+
+
+
+ ); +}; + +export default GameList; \ No newline at end of file diff --git a/src/pages/Home2.js b/src/pages/Home2.js index 33e3896..2decee5 100644 --- a/src/pages/Home2.js +++ b/src/pages/Home2.js @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; -import { BarChart2, Calendar, RefreshCw } from 'lucide-react'; +import { BarChart2, Calendar, RefreshCw, Clock, ChevronLeft, ChevronRight } from 'lucide-react'; import axios from 'axios'; +import TodaysMatch from './TodaysMatch'; const Home2 = () => { const [teams, setTeams] = useState([]); @@ -13,73 +14,105 @@ const Home2 = () => { const [error, setError] = useState(null); const [calendarData, setCalendarData] = useState([]); const [currentMonth, setCurrentMonth] = useState(new Date()); + const [upcomingMatches, setUpcomingMatches] = useState([]); // API URL const API_URL = 'http://localhost:5500/api'; + // Format time + const formatTime = (timeString) => { + try { + const date = new Date(timeString); + return date.toLocaleTimeString("en-US", { hour: '2-digit', minute: '2-digit', hour12: true }); + } catch (e) { + return "XX:XX"; + } + }; + + // Check if a match is upcoming + const isUpcoming = (resultTime) => { + try { + const now = new Date(); + const matchTime = new Date(resultTime); + return matchTime > now; + } catch (e) { + return false; + } + }; + // Fetch teams data useEffect(() => { - - const fetchTeams = async () => { + const fetchData = async () => { try { setLoading(true); + // Get all teams const teamsResponse = await axios.get(`${API_URL}/teams`); - alert("teamsResponse"); // Get today's date and format it const today = new Date(); const todayFormatted = today.toISOString().split('T')[0]; + // Get yesterday's date and format it const yesterday = new Date(); yesterday.setDate(yesterday.getDate() - 1); const yesterdayFormatted = yesterday.toISOString().split('T')[0]; - + // Set dates for display setDates([yesterdayFormatted, todayFormatted]); - + // Get today's results - const todayResultsResponse = await axios.get(`${API_URL}/today`); - - // Get yesterday's results for each team - const yesterdayResultsPromises = teamsResponse.data.map(team => - axios.get(`${API_URL}/results?team=${team.name}&date=${yesterdayFormatted}`) - .then(response => response.data) - .catch(() => null) // If no result, return null - ); - - const yesterdayResults = await Promise.all(yesterdayResultsPromises); - + const todayResultsResponse = await axios.get(`${API_URL}/results/daily?date=${todayFormatted}`); + const todayResults = todayResultsResponse.data; + + // Get yesterday's results + const yesterdayResultsResponse = await axios.get(`${API_URL}/results/daily?date=${yesterdayFormatted}`); + const yesterdayResults = yesterdayResultsResponse.data; + + // Process upcoming matches + const upcoming = todayResults.filter(result => isUpcoming(result.result_time)); + setUpcomingMatches(upcoming); + // Combine team data with results - const teamsWithResults = teamsResponse.data.map((team, index) => { - const results = {}; - - // Add yesterday's result if available - if (yesterdayResults[index]) { - results[yesterdayFormatted] = yesterdayResults[index].result; + const teamsWithResults = teamsResponse.data.map(team => { + // Get all results for this team + const yesterdayTeamResults = yesterdayResults.filter(r => r.team === team.name); + const todayTeamResults = todayResults.filter(r => r.team === team.name); + + // Create result arrays for both days + const yesterdayResultsArr = yesterdayTeamResults.map(r => ({ + result: r.visible_result, + time: formatTime(r.result_time) + })); + + const todayResultsArr = todayTeamResults + .filter(r => !isUpcoming(r.result_time)) + .map(r => ({ + result: r.visible_result, + time: formatTime(r.result_time) + })); + + // Extract latest scheduled time + let latestTime = "XX:XX"; + const latestTodayResult = todayTeamResults + .sort((a, b) => new Date(b.result_time) - new Date(a.result_time)) + .find(r => r.result_time); + + if (latestTodayResult) { + latestTime = formatTime(latestTodayResult.result_time); } - - // Add today's result if available - const todayResult = todayResultsResponse.data.find(r => r.team === team.name); - if (todayResult) { - results[todayFormatted] = todayresult.visible_result; - } - - // Extract time from team name or use default - let time = "XX:XX"; - const timePart = team.name.match(/\d{2}:\d{2}\s*(?:AM|PM)/i); - if (timePart) { - time = timePart[0]; - } - + return { id: team.id, name: team.name, - time: time, - results: results + time: latestTime, + results: { + [yesterdayFormatted]: yesterdayResultsArr, + [todayFormatted]: todayResultsArr + } }; }); - + setTeams(teamsWithResults); setLoading(false); } catch (err) { @@ -88,21 +121,21 @@ const Home2 = () => { setLoading(false); } }; - - fetchTeams(); - + + fetchData(); + // Update current time every minute const interval = setInterval(() => { const now = new Date(); const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" }); setCurrentTime(formattedTime); }, 60000); - + // Set initial time const now = new Date(); const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" }); setCurrentTime(formattedTime); - + return () => clearInterval(interval); }, []); @@ -114,17 +147,17 @@ const Home2 = () => { const currentDate = new Date(); const month = currentDate.getMonth() + 1; const year = currentDate.getFullYear(); - + const response = await axios.post(`${API_URL}/results/monthly`, { team: team.name, month: `${year}-${month.toString().padStart(2, '0')}` }); - + setSelectedTeam({ ...team, chartData: response.data }); - + setShowChartView(true); setShowCalendar(false); setLoading(false); @@ -139,16 +172,16 @@ const Home2 = () => { const loadCalendarData = async (year, month) => { try { setLoading(true); - + // Calculate first and last day of month const firstDay = new Date(year, month, 1).toISOString().split('T')[0]; const lastDay = new Date(year, month + 1, 0).toISOString().split('T')[0]; - + // Get results for each day in the month const dailyResultsPromises = []; const currentDate = new Date(year, month, 1); const lastDate = new Date(year, month + 1, 0); - + while (currentDate <= lastDate) { const dateString = currentDate.toISOString().split('T')[0]; dailyResultsPromises.push( @@ -164,40 +197,55 @@ const Home2 = () => { ); currentDate.setDate(currentDate.getDate() + 1); } - + const allResults = await Promise.all(dailyResultsPromises); - + // Format calendar data const calendarDays = []; const firstDayOfMonth = new Date(year, month, 1); const firstDayWeekday = firstDayOfMonth.getDay(); - + // Add empty cells for days before the first of the month for (let i = 0; i < firstDayWeekday; i++) { calendarDays.push(null); } - + // Add days with results for (let i = 1; i <= lastDate.getDate(); i++) { const dateObj = new Date(year, month, i); const dateStr = dateObj.toISOString().split('T')[0]; - + const dayData = allResults.find(r => r.date === dateStr); - let teamResults = {}; - + let dayResults = []; + if (dayData && dayData.results.length > 0) { + // Group by team + const teamResults = {}; + dayData.results.forEach(result => { - teamResults[result.team] = result.visible_result; + if (!teamResults[result.team]) { + teamResults[result.team] = []; + } + teamResults[result.team].push({ + result: result.visible_result, + time: formatTime(result.result_time) + }); }); + + // Create an array for display + dayResults = Object.entries(teamResults).map(([team, results]) => ({ + team, + results + })); } - + calendarDays.push({ day: i, date: dateStr, - results: teamResults + results: dayResults }); } - + setCalendarData(calendarDays); setLoading(false); } catch (err) { @@ -229,243 +277,128 @@ const Home2 = () => { window.location.reload(); }; + // Format date for display + const formatDate = (dateString) => { + return new Date(dateString).toLocaleDateString('en-US', { + weekday: 'short', + month: 'long', + day: 'numeric', + year: 'numeric' + }); + }; + + + const [openIndex, setOpenIndex] = useState(null); + + const toggleFAQ = (index) => { + setOpenIndex(openIndex === index ? null : index); + }; + + const faqs = [ + { question: "HOW TO PLAY", answer: "Details about how to play." }, + { question: "WHERE TO PLAY", answer: "Information on where to play." }, + { question: "WINNING NUMBERS EMAIL", answer: "Sign up for emails." }, + ]; + return ( -
-
+
+
{/* Header */} -

SATTA-KING-FAST.com

- +

+ Advertisement +

+ {/* Advertisement Banner */} -
- Advertisement + Advertisement
- + {/* Informational Text */} -

- Delhi Diamond Satta Result And Monthly Satta Chart of March 2025 With Combined Chart of Gali, Desawar, Ghaziabad, Faridabad And Shri Ganesh from Satta King Fast, Satta King Result, Satta King Chart, Black Satta King and Satta King 786. +

+ Delhi Diamond Satta Result And Monthly Satta Chart of March 2025 With Combined Chart of Gali, Desawar, Ghaziabad, Faridabad And Shri Ganesh from Matka Satta Fast, Matka Satta Result, Matka Satta Chart, Black Matka Satta and Matka Satta 786.

- + {/* Disclaimer */} -

- Satta-King-Fast.com is the most popular gaming discussion forum for players to use freely and we are not in partnership with any gaming company. +

+ Matka-Satta .com is the most popular gaming discussion forum for players to use freely and we are not in partnership with any gaming company.

- + {/* Warning Message */} -

+

कृपया ध्यान दें, लीक गेम के नाम पर किसी को कोई पैसा न दें, ना पहले ना बाद में - धन्यवाद

- + {/* Contact Link */} -

- हमसे संपर्क करने के लिए ➡ यहाँ क्लिक करें +

+ हमसे संपर्क करने के लिए ➡ यहाँ क्लिक करें

- + {/* Timestamp */} -

+

Updated: {currentTime} IST.

+
-
- {error && ( -
-

{error}

-
- )} - -
- {teams.length > 0 && teams[0].name} Satta Result of {dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })} & {dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })} -
- - {/* Controls */} -
-
Latest Results
- -
- - -
-
- - {/* Loading indicator */} - {loading && ( -
-
- - Loading data... -
-
- )} - - {/* Chart View */} - {!loading && showChartView && selectedTeam && ( -
-

Monthly Chart: {selectedTeam.name}

-
- - - - - - - - - {selectedTeam.chartData && selectedTeam.chartData.map((item, index) => ( - - - - - ))} - {(!selectedTeam.chartData || selectedTeam.chartData.length === 0) && ( - - - - )} - -
DateResult
{new Date(item.result_date).toLocaleDateString()}{item.result}
No chart data available
-
-
-
+ + + +
+ {/* FAQ Section */} +
+ {faqs.map((faq, index) => ( +
+ -
-
- )} - - {/* Calendar View */} - {!loading && showCalendar && ( -
-
- - -

- {currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })} -

- - -
- -
- {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => ( -
{day}
- ))} -
- -
- {calendarData.map((day, index) => ( -
- {day && ( - <> -
{day.day}
- {teams.map(team => ( -
- {day.results[team.name] && ( - <> - {team.name.split(' ')[0]}: {day.results[team.name]} - - )} -
- ))} - - )} + {openIndex === index && ( +
+ {faq.answer}
- ))} -
- -
- + )}
+ ))} +
+ + {/* Footer Section */} +
+
+

+ MATKA SATTA +

+

+ The Multi-State Lottery Association makes every effort to ensure the + accuracy of winning numbers and other information. Official winning + numbers are those selected in the respective drawings and recorded + under the observation of an independent accounting firm. +

+

+ In the event of a discrepancy, the official drawing results shall + prevail. All winning tickets must be redeemed in the + state/jurisdiction in which they are sold. +

+

+ Media Center + Legal + Privacy + español +

- )} - - {/* Teams Table */} - {!loading && !showCalendar && !showChartView && ( -
- - - - - - - - - - - {teams.map(team => ( - - - - - - - ))} - {teams.length === 0 && ( - - - - )} - -
Games List - {dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 0 && new Date(dates[0]).getDate()}th - - {dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 1 && new Date(dates[1]).getDate()}th - Chart
-
{team.name}
-
at {team.time}
-
handleViewChart(team)}>Record Chart
-
{dates.length > 0 && team.results[dates[0]] || 'XX'}{dates.length > 1 && team.results[dates[1]] || 'XX'} -
- -
-
No teams found
- -
- -
-
- )} +
); diff --git a/src/pages/Home3.js b/src/pages/Home3.js new file mode 100644 index 0000000..d48e6d9 --- /dev/null +++ b/src/pages/Home3.js @@ -0,0 +1,682 @@ +import React, { useState, useEffect } from 'react'; +import { BarChart2, Calendar, RefreshCw, Clock, ChevronLeft, ChevronRight } from 'lucide-react'; +import axios from 'axios'; +import TodaysMatch from './TodaysMatch'; + +const Home2 = () => { + const [teams, setTeams] = useState([]); + const [dates, setDates] = useState([]); + const [selectedTeam, setSelectedTeam] = useState(null); + const [showChartView, setShowChartView] = useState(false); + const [showCalendar, setShowCalendar] = useState(false); + const [currentTime, setCurrentTime] = useState(""); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [calendarData, setCalendarData] = useState([]); + const [currentMonth, setCurrentMonth] = useState(new Date()); + const [upcomingMatches, setUpcomingMatches] = useState([]); + + // API URL + const API_URL = 'http://localhost:5500/api'; + + // Format time + const formatTime = (timeString) => { + try { + const date = new Date(timeString); + return date.toLocaleTimeString("en-US", { hour: '2-digit', minute: '2-digit', hour12: true }); + } catch (e) { + return "XX:XX"; + } + }; + + // Check if a match is upcoming + const isUpcoming = (resultTime) => { + try { + const now = new Date(); + const matchTime = new Date(resultTime); + return matchTime > now; + } catch (e) { + return false; + } + }; + + // Fetch teams data + useEffect(() => { + const fetchData = async () => { + try { + setLoading(true); + + // Get all teams + const teamsResponse = await axios.get(`${API_URL}/teams`); + + // Get today's date and format it + const today = new Date(); + const todayFormatted = today.toISOString().split('T')[0]; + + // Get yesterday's date and format it + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + const yesterdayFormatted = yesterday.toISOString().split('T')[0]; + + // Set dates for display + setDates([yesterdayFormatted, todayFormatted]); + + // Get today's results + const todayResultsResponse = await axios.get(`${API_URL}/results/daily?date=${todayFormatted}`); + const todayResults = todayResultsResponse.data; + + // Get yesterday's results + const yesterdayResultsResponse = await axios.get(`${API_URL}/results/daily?date=${yesterdayFormatted}`); + const yesterdayResults = yesterdayResultsResponse.data; + + // Process upcoming matches + const upcoming = todayResults.filter(result => isUpcoming(result.result_time)); + setUpcomingMatches(upcoming); + + // Combine team data with results + const teamsWithResults = teamsResponse.data.map(team => { + // Get all results for this team + const yesterdayTeamResults = yesterdayResults.filter(r => r.team === team.name); + const todayTeamResults = todayResults.filter(r => r.team === team.name); + + // Create result arrays for both days + const yesterdayResultsArr = yesterdayTeamResults.map(r => ({ + result: r.visible_result, + time: formatTime(r.result_time) + })); + + const todayResultsArr = todayTeamResults + .filter(r => !isUpcoming(r.result_time)) + .map(r => ({ + result: r.visible_result, + time: formatTime(r.result_time) + })); + + // Extract latest scheduled time + let latestTime = "XX:XX"; + const latestTodayResult = todayTeamResults + .sort((a, b) => new Date(b.result_time) - new Date(a.result_time)) + .find(r => r.result_time); + + if (latestTodayResult) { + latestTime = formatTime(latestTodayResult.result_time); + } + + return { + id: team.id, + name: team.name, + time: latestTime, + results: { + [yesterdayFormatted]: yesterdayResultsArr, + [todayFormatted]: todayResultsArr + } + }; + }); + + setTeams(teamsWithResults); + setLoading(false); + } catch (err) { + console.error("Error fetching data:", err); + setError("Failed to load team data. Please try again later."); + setLoading(false); + } + }; + + fetchData(); + + // Update current time every minute + const interval = setInterval(() => { + const now = new Date(); + const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" }); + setCurrentTime(formattedTime); + }, 60000); + + // Set initial time + const now = new Date(); + const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" }); + setCurrentTime(formattedTime); + + return () => clearInterval(interval); + }, []); + + // Show chart for selected team + const handleViewChart = async (team) => { + try { + setLoading(true); + // Get monthly results for the selected team + const currentDate = new Date(); + const month = currentDate.getMonth() + 1; + const year = currentDate.getFullYear(); + + const response = await axios.post(`${API_URL}/results/monthly`, { + team: team.name, + month: `${year}-${month.toString().padStart(2, '0')}` + }); + + setSelectedTeam({ + ...team, + chartData: response.data + }); + + setShowChartView(true); + setShowCalendar(false); + setLoading(false); + } catch (err) { + console.error("Error fetching chart data:", err); + setError("Failed to load chart data. Please try again later."); + setLoading(false); + } + }; + + // Load calendar data + const loadCalendarData = async (year, month) => { + try { + setLoading(true); + + // Calculate first and last day of month + const firstDay = new Date(year, month, 1).toISOString().split('T')[0]; + const lastDay = new Date(year, month + 1, 0).toISOString().split('T')[0]; + + // Get results for each day in the month + const dailyResultsPromises = []; + const currentDate = new Date(year, month, 1); + const lastDate = new Date(year, month + 1, 0); + + while (currentDate <= lastDate) { + const dateString = currentDate.toISOString().split('T')[0]; + dailyResultsPromises.push( + axios.get(`${API_URL}/results/daily?date=${dateString}`) + .then(response => ({ + date: dateString, + results: response.data + })) + .catch(() => ({ + date: dateString, + results: [] + })) + ); + currentDate.setDate(currentDate.getDate() + 1); + } + + const allResults = await Promise.all(dailyResultsPromises); + + // Format calendar data + const calendarDays = []; + const firstDayOfMonth = new Date(year, month, 1); + const firstDayWeekday = firstDayOfMonth.getDay(); + + // Add empty cells for days before the first of the month + for (let i = 0; i < firstDayWeekday; i++) { + calendarDays.push(null); + } + + // Add days with results + for (let i = 1; i <= lastDate.getDate(); i++) { + const dateObj = new Date(year, month, i); + const dateStr = dateObj.toISOString().split('T')[0]; + + const dayData = allResults.find(r => r.date === dateStr); + let dayResults = []; + + if (dayData && dayData.results.length > 0) { + // Group by team + const teamResults = {}; + + dayData.results.forEach(result => { + if (!teamResults[result.team]) { + teamResults[result.team] = []; + } + teamResults[result.team].push({ + result: result.visible_result, + time: formatTime(result.result_time) + }); + }); + + // Create an array for display + dayResults = Object.entries(teamResults).map(([team, results]) => ({ + team, + results + })); + } + + calendarDays.push({ + day: i, + date: dateStr, + results: dayResults + }); + } + + setCalendarData(calendarDays); + setLoading(false); + } catch (err) { + console.error("Error loading calendar data:", err); + setError("Failed to load calendar data. Please try again later."); + setLoading(false); + } + }; + + // Handle calendar view button click + const handleCalendarView = () => { + const now = new Date(); + setCurrentMonth(now); + loadCalendarData(now.getFullYear(), now.getMonth()); + setShowCalendar(true); + setShowChartView(false); + }; + + // Handle month change in calendar + const handleMonthChange = (increment) => { + const newMonth = new Date(currentMonth); + newMonth.setMonth(newMonth.getMonth() + increment); + setCurrentMonth(newMonth); + loadCalendarData(newMonth.getFullYear(), newMonth.getMonth()); + }; + + // Refresh data + const handleRefresh = () => { + window.location.reload(); + }; + + // Format date for display + const formatDate = (dateString) => { + return new Date(dateString).toLocaleDateString('en-US', { + weekday: 'short', + month: 'long', + day: 'numeric', + year: 'numeric' + }); + }; + + + const [openIndex, setOpenIndex] = useState(null); + + const toggleFAQ = (index) => { + setOpenIndex(openIndex === index ? null : index); + }; + + const faqs = [ + { question: "HOW TO PLAY", answer: "Details about how to play." }, + { question: "WHERE TO PLAY", answer: "Information on where to play." }, + { question: "WINNING NUMBERS EMAIL", answer: "Sign up for emails." }, + ]; + + return ( +
+
+ {/* Header */} +

+ Advertisement +

+ + {/* Advertisement Banner */} +
+ Advertisement +
+ + {/* Informational Text */} +

+ Delhi Diamond Satta Result And Monthly Satta Chart of March 2025 With Combined Chart of Gali, Desawar, Ghaziabad, Faridabad And Shri Ganesh from Matka Satta Fast, Matka Satta Result, Matka Satta Chart, Black Matka Satta and Matka Satta 786. +

+ + {/* Disclaimer */} +

+ Matka-Satta .com is the most popular gaming discussion forum for players to use freely and we are not in partnership with any gaming company. +

+ + {/* Warning Message */} +

+ कृपया ध्यान दें, लीक गेम के नाम पर किसी को कोई पैसा न दें, ना पहले ना बाद में - धन्यवाद +

+ + {/* Contact Link */} +

+ हमसे संपर्क करने के लिए ➡ यहाँ क्लिक करें +

+ + {/* Timestamp */} +

+ Updated: {currentTime} IST. +

+
+ +
+ {error && ( +
+

{error}

+
+ )} + + +
+ Satta Result of {dates.length > 1 && formatDate(dates[1])} & {dates.length > 0 && formatDate(dates[0])} +
+ + {/* Controls */} +
+
Latest Results
+ +
+ + +
+
+ + {/* Loading indicator */} + {loading && ( +
+
+ + Loading data... +
+
+ )} + + {/* Upcoming Matches */} + {!loading && upcomingMatches.length > 0 && !showChartView && !showCalendar && ( +
+

+ + Upcoming Matches Today +

+
+ + + + + + + + + {upcomingMatches.map((match, index) => ( + + + + + ))} + +
TeamScheduled Time
{match.team}{formatTime(match.result_time)}
+
+
+ )} + + {/* Chart View */} + {!loading && showChartView && selectedTeam && ( +
+

Monthly Chart: {selectedTeam.name}

+
+ + + + + + + + + + {selectedTeam.chartData && selectedTeam.chartData.map((item, index) => ( + + + + + + ))} + {(!selectedTeam.chartData || selectedTeam.chartData.length === 0) && ( + + + + )} + +
DateTimeResult
{new Date(item.result_date).toLocaleDateString()}{formatTime(item.result_time)}{item.result}
No chart data available
+
+
+ +
+
+ )} + + {/* Calendar View - Improved Responsive Design */} + {!loading && showCalendar && ( +
+
+ + +

+ {currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })} +

+ + +
+ +
+ {['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => ( +
{day}
+ ))} +
+ +
+ {calendarData.map((day, index) => ( +
+ {day && ( + <> +
+ {day.day} +
+
+ {day.results.length > 0 ? ( + day.results.map((teamResult, i) => ( +
+
{teamResult.team}
+ {teamResult.results.map((r, j) => ( +
+ {r.time} + {r.result} +
+ ))} +
+ )) + ) : ( +
No results
+ )} +
+ + )} +
+ ))} +
+ +
+ +
+
+ )} + + {/* Teams Table with multiple results support */} + {!loading && !showCalendar && !showChartView && ( +
+ + + + + + + + + + + {teams.map(team => ( + + + + + + + + + + ))} + {teams.length === 0 && ( + + + + )} + +
Games List + {dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 0 && new Date(dates[0]).getDate()}th + + {dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 1 && new Date(dates[1]).getDate()}th + Chart
+
{team.name}
+
at {team.time}
+
handleViewChart(team)}>Record Chart
+
+ {dates.length > 0 && team.results[dates[0]] && team.results[dates[0]].length > 0 ? ( +
+ {team.results[dates[0]].map((result, idx) => ( +
+ {result.result} + {result.time} +
+ ))} +
+ ) : ( + XX + )} +
+ {dates.length > 1 && team.results[dates[1]] && team.results[dates[1]].length > 0 ? ( +
+ {team.results[dates[1]].map((result, idx) => ( +
+ {result.result} + {result.time} +
+ ))} +
+ ) : ( + XX + )} +
+
+ +
+
No teams found
+ +
+ +
+
+ )} +
+ +
+ {/* FAQ Section */} +
+ {faqs.map((faq, index) => ( +
+ + {openIndex === index && ( +
+ {faq.answer} +
+ )} +
+ ))} +
+ + {/* Footer Section */} +
+
+

+ MATKA SATTA +

+

+ The Multi-State Lottery Association makes every effort to ensure the + accuracy of winning numbers and other information. Official winning + numbers are those selected in the respective drawings and recorded + under the observation of an independent accounting firm. +

+

+ In the event of a discrepancy, the official drawing results shall + prevail. All winning tickets must be redeemed in the + state/jurisdiction in which they are sold. +

+

+ Media Center + Legal + Privacy + español +

+
+
+
+
+ ); +}; + +export default Home2; \ No newline at end of file diff --git a/src/pages/Today.js b/src/pages/Today.js new file mode 100644 index 0000000..5118fbe --- /dev/null +++ b/src/pages/Today.js @@ -0,0 +1,282 @@ +import React, { useState, useEffect } from 'react'; +import { RefreshCw, Clock, ChevronDown, ChevronUp, Calendar } from 'lucide-react'; +import axios from 'axios'; + +const Today = () => { + const [todaysMatches, setTodaysMatches] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [currentDate, setCurrentDate] = useState(''); + const [expandedTeams, setExpandedTeams] = useState({}); + + // API URL + const API_URL = 'http://localhost:5500/api'; + + // Format time + const formatTime = (timeString) => { + try { + const date = new Date(timeString); + return date.toLocaleTimeString("en-US", { hour: '2-digit', minute: '2-digit', hour12: true }); + } catch (e) { + return "XX:XX"; + } + }; + + // Toggle team expansion + const toggleTeamExpansion = (team) => { + setExpandedTeams(prev => ({ + ...prev, + [team]: !prev[team] + })); + }; + + // Fetch today's matches + useEffect(() => { + const fetchTodaysMatches = async () => { + try { + setLoading(true); + + // Get today's date for display + const today = new Date(); + setCurrentDate(today.toLocaleDateString('en-US', { + weekday: 'short', + month: 'long', + day: 'numeric', + year: 'numeric' + })); + + // Get today's results + const todayResultsResponse = await axios.get(`${API_URL}/today`); + const todayResults = todayResultsResponse.data; + + // Group by team + const teamResults = {}; + + todayResults.forEach(result => { + if (!teamResults[result.team]) { + teamResults[result.team] = []; + } + teamResults[result.team].push({ + result: result.visible_result, + time: formatTime(result.result_time), + timestamp: new Date(result.result_time), + upcoming: new Date(result.result_time) > new Date() + }); + }); + + // Convert to array for display and initialize expanded state + const groupedResults = Object.entries(teamResults).map(([team, results]) => { + // Sort by time + const sortedResults = results.sort((a, b) => a.timestamp - b.timestamp); + + // Set all teams expanded by default + setExpandedTeams(prev => ({ + ...prev, + [team]: true + })); + + return { + team, + results: sortedResults, + upcomingCount: sortedResults.filter(r => r.upcoming).length, + completedCount: sortedResults.filter(r => !r.upcoming).length + }; + }); + + setTodaysMatches(groupedResults); + setLoading(false); + } catch (err) { + console.error("Error fetching today's matches:", err); + setError("Failed to load today's match data. Please try again later."); + setLoading(false); + } + }; + + fetchTodaysMatches(); + }, []); + + // Refresh data + const handleRefresh = () => { + setLoading(true); + setError(null); + + const fetchData = async () => { + try { + // Get today's results + const todayResultsResponse = await axios.get(`${API_URL}/today`); + const todayResults = todayResultsResponse.data; + + // Group by team + const teamResults = {}; + + todayResults.forEach(result => { + if (!teamResults[result.team]) { + teamResults[result.team] = []; + } + teamResults[result.team].push({ + result: result.visible_result, + time: formatTime(result.result_time), + timestamp: new Date(result.result_time), + upcoming: new Date(result.result_time) > new Date() + }); + }); + + // Convert to array for display + const groupedResults = Object.entries(teamResults).map(([team, results]) => { + // Sort by time + const sortedResults = results.sort((a, b) => a.timestamp - b.timestamp); + + return { + team, + results: sortedResults, + upcomingCount: sortedResults.filter(r => r.upcoming).length, + completedCount: sortedResults.filter(r => !r.upcoming).length + }; + }); + + setTodaysMatches(groupedResults); + setLoading(false); + } catch (err) { + setError("Failed to refresh match data. Please try again later."); + setLoading(false); + } + }; + + fetchData(); + }; + + // Get status badge + const getStatusBadge = (result) => { + if (result.upcoming) { + return ( + + Upcoming + + ); + } + + // You could add logic here to style different results differently + // For example, showing wins in green, losses in red + return ( + + Completed + + ); + }; + + return ( +
+ {/* Header */} +
+
+

Today's Matches

+
+ + {currentDate} +
+
+
+ + {/* Controls */} +
+
+ {todaysMatches.length > 0 ? + `${todaysMatches.length} teams with matches today` : + "No matches scheduled"} +
+ +
+ + {/* Loading indicator */} + {loading && ( +
+
+ + Loading match data... +
+
+ )} + + {/* Error message */} + {error && ( +
+
+
+

{error}

+
+
+
+ )} + + {/* Results display */} + {!loading && !error && ( +
+ {todaysMatches.length > 0 ? ( +
+ {todaysMatches.map((teamData, index) => ( +
+ {/* Team header - clickable to expand/collapse */} +
toggleTeamExpansion(teamData.team)} + > +
{teamData.team}
+
+
+ {teamData.upcomingCount} upcoming • {teamData.completedCount} completed +
+ {expandedTeams[teamData.team] ? ( + + ) : ( + + )} +
+
+ + {/* Team results */} + {expandedTeams[teamData.team] && ( +
+ {teamData.results.map((result, idx) => ( +
+
+ + {result.time} + {getStatusBadge(result)} +
+
+ {result.upcoming ? ( + -- + ) : ( + {result.result} + )} +
+
+ ))} +
+ )} +
+ ))} +
+ ) : ( +
+
+ +
+

No matches today

+

There are no matches scheduled for today.

+
+ )} +
+ )} +
+ ); +}; + +export default Today; \ No newline at end of file diff --git a/src/pages/TodaysMatch.js b/src/pages/TodaysMatch.js new file mode 100644 index 0000000..d2bf62f --- /dev/null +++ b/src/pages/TodaysMatch.js @@ -0,0 +1,298 @@ +import React, { useState, useEffect } from 'react'; +import { RefreshCw, Clock, ChevronRight, ChevronLeft } from 'lucide-react'; +import axios from 'axios'; + +const TodaysMatch = () => { + const [todaysMatches, setTodaysMatches] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [currentDate, setCurrentDate] = useState(''); + const [activeTeamIndex, setActiveTeamIndex] = useState(0); + + // API URL + const API_URL = 'http://localhost:5500/api'; + + // Format time + const formatTime = (timeString) => { + try { + const date = new Date(timeString); + return date.toLocaleTimeString("en-US", { hour: '2-digit', minute: '2-digit', hour12: true }); + } catch (e) { + return "XX:XX"; + } + }; + + // Fetch today's matches + useEffect(() => { + const fetchTodaysMatches = async () => { + try { + setLoading(true); + + // Get today's date for display + const today = new Date(); + setCurrentDate(today.toLocaleDateString('en-US', { + weekday: 'short', + month: 'long', + day: 'numeric', + year: 'numeric' + })); + + // Get today's results + const todayResultsResponse = await axios.get(`${API_URL}/today`); + const todayResults = todayResultsResponse.data; + + // Group by team + const teamResults = {}; + + todayResults.forEach(result => { + if (!teamResults[result.team]) { + teamResults[result.team] = []; + } + teamResults[result.team].push({ + result: result.visible_result, + time: formatTime(result.result_time), + upcoming: new Date(result.result_time) > new Date() + }); + }); + + // Convert to array for display + const groupedResults = Object.entries(teamResults).map(([team, results]) => ({ + team, + results: results.sort((a, b) => a.upcoming - b.upcoming) + })); + + setTodaysMatches(groupedResults); + setLoading(false); + } catch (err) { + console.error("Error fetching today's matches:", err); + setError("Failed to load today's match data. Please try again later."); + setLoading(false); + } + }; + + fetchTodaysMatches(); + }, []); + + // Navigation handlers + const handleNext = () => { + if (todaysMatches.length > 0) { + setActiveTeamIndex((prevIndex) => + prevIndex === todaysMatches.length - 1 ? 0 : prevIndex + 1 + ); + } + }; + + const handlePrev = () => { + if (todaysMatches.length > 0) { + setActiveTeamIndex((prevIndex) => + prevIndex === 0 ? todaysMatches.length - 1 : prevIndex - 1 + ); + } + }; + + // Refresh data + const handleRefresh = () => { + setLoading(true); + setError(null); + + const fetchData = async () => { + try { + const todayResultsResponse = await axios.get(`${API_URL}/today`); + const todayResults = todayResultsResponse.data; + + const teamResults = {}; + + todayResults.forEach(result => { + if (!teamResults[result.team]) { + teamResults[result.team] = []; + } + teamResults[result.team].push({ + result: result.visible_result, + time: formatTime(result.result_time), + upcoming: new Date(result.result_time) > new Date() + }); + }); + + const groupedResults = Object.entries(teamResults).map(([team, results]) => ({ + team, + results: results.sort((a, b) => a.upcoming - b.upcoming) + })); + + setTodaysMatches(groupedResults); + setLoading(false); + } catch (err) { + setError("Failed to refresh match data. Please try again later."); + setLoading(false); + } + }; + + fetchData(); + }; + + // Render boxes similar to lottery design + return ( +
+ {/* Today's Matches Box */} +
+
+

Winning Numbers

+
+
+

{currentDate}

+ + {loading ? ( +
+ +
+ ) : error ? ( +
+

{error}

+
+ ) : todaysMatches.length > 0 ? ( +
+ {/* Navigation buttons */} + + + + + {/* Current team results */} +
+
+ {todaysMatches[activeTeamIndex]?.team || "No Team"} +
+ +
+ {todaysMatches[activeTeamIndex]?.results.map((result, idx) => ( +
+
+ + {result.time} +
+
+ {result.upcoming ? "Upcoming" : result.result} +
+
+ ))} +
+
+ + {/* Team indicators */} +
+ {todaysMatches.map((_, idx) => ( +
+ ))} +
+
+ ) : ( +
+ No match results available for today. +
+ )} + + + + {/*
+ + +
*/} +
+
+ + {/* Next Drawing Box */} +
+
+

Next Drawing

+
+
+

Sat, Mar 22, 2025

+ +
+
+
67
+
+
+
58
+
+
+
11
+
+
+ +
+
HOURS
+
MINUTES
+
SECONDS
+
+ +
+ ESTIMATED JACKPOT +
+ +
+ $444 Million +
+ +
+ CASH VALUE +
+ +
+ $207.2 Million +
+
+
+ + {/* Winners Box */} +
+
+

Winners

+
+
+

Wed, Mar 19, 2025

+ +
+
POWERBALL
+
JACKPOT WINNERS
+
None
+
+ +
+
MATCH 5 + POWER PLAY
+
$2 MILLION WINNERS
+
CO, TX
+
+ +
+
MATCH 5
+
$1 MILLION WINNERS
+
None
+
+
+
+
+ ); +}; + +export default TodaysMatch; \ No newline at end of file