updated user view

This commit is contained in:
shivam 2025-03-20 23:06:10 +05:30
parent 67a9ab2a45
commit 48d00e12db
10 changed files with 2408 additions and 483 deletions

30
package-lock.json generated
View File

@ -13,11 +13,13 @@
"@testing-library/react": "^16.2.0", "@testing-library/react": "^16.2.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^1.8.3", "axios": "^1.8.3",
"chart.js": "^4.4.8",
"cors": "^2.8.5", "cors": "^2.8.5",
"http": "^0.0.1-security", "http": "^0.0.1-security",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"lucide-react": "^0.479.0", "lucide-react": "^0.479.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-chartjs-2": "^5.3.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-router-dom": "^7.3.0", "react-router-dom": "^7.3.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
@ -2785,6 +2787,12 @@
"@jridgewell/sourcemap-codec": "^1.4.14" "@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": { "node_modules/@leichtgewicht/ip-codec": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz",
@ -5348,6 +5356,18 @@
"node": ">=10" "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": { "node_modules/check-types": {
"version": "11.2.3", "version": "11.2.3",
"resolved": "https://registry.npmjs.org/check-types/-/check-types-11.2.3.tgz", "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", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" "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": { "node_modules/react-dev-utils": {
"version": "12.0.1", "version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",

View File

@ -8,11 +8,13 @@
"@testing-library/react": "^16.2.0", "@testing-library/react": "^16.2.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^1.8.3", "axios": "^1.8.3",
"chart.js": "^4.4.8",
"cors": "^2.8.5", "cors": "^2.8.5",
"http": "^0.0.1-security", "http": "^0.0.1-security",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"lucide-react": "^0.479.0", "lucide-react": "^0.479.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-chartjs-2": "^5.3.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-router-dom": "^7.3.0", "react-router-dom": "^7.3.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",

BIN
public/add.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
public/logo.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -4,6 +4,8 @@ import './App.css';
import { useParams, useNavigate, useLocation } from 'react-router-dom'; import { useParams, useNavigate, useLocation } from 'react-router-dom';
import Home from './pages/Home'; import Home from './pages/Home';
import TeamResults from './pages/TeamResult'; import TeamResults from './pages/TeamResult';
import Home2 from './pages/Home2';
import GameList from './pages/GameList';
// Auth Context // Auth Context
const AuthContext = React.createContext(); const AuthContext = React.createContext();
@ -133,6 +135,9 @@ const apiService = {
}, },
updateResult: async (id, resultData, token) => { updateResult: async (id, resultData, token) => {
console.log(`Updating result ${id} with data:`, resultData);
try {
const response = await fetch(`${API_URL}/admin/results/${id}`, { const response = await fetch(`${API_URL}/admin/results/${id}`, {
method: 'PUT', method: 'PUT',
headers: { headers: {
@ -143,23 +148,40 @@ const apiService = {
}); });
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to update result'); // 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 response.json(); return await response.json();
} catch (error) {
console.error("Error in updateResult:", error);
throw error;
}
}, },
deleteResult: async (id, token) => { deleteResult: async (id, token) => {
console.log(`Deleting result ${id}`);
try {
const response = await fetch(`${API_URL}/admin/results/${id}`, { const response = await fetch(`${API_URL}/admin/results/${id}`, {
method: 'DELETE', method: 'DELETE',
headers: { 'Authorization': `Bearer ${token}` } headers: { 'Authorization': `Bearer ${token}` }
}); });
if (!response.ok) { if (!response.ok) {
throw new Error('Failed to delete result'); // 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 response.json(); return await response.json();
} catch (error) {
console.error("Error in deleteResult:", error);
throw error;
}
}, },
getDailyResults: async (date, token) => { getDailyResults: async (date, token) => {
@ -320,7 +342,7 @@ const TeamList = () => {
try { try {
const data = await apiService.getTeams(token); const data = await apiService.getTeams(token);
setTeams(data); setTeams(data);
// alert(teams) alert(teams)
setLoading(false); setLoading(false);
} catch (err) { } catch (err) {
setError('Failed to fetch teams'); setError('Failed to fetch teams');
@ -394,6 +416,7 @@ const TeamForm = ({ isEdit = false }) => {
const teams = await apiService.getTeams(token); const teams = await apiService.getTeams(token);
const team = teams.find(t => t.id === parseInt(id)); const team = teams.find(t => t.id === parseInt(id));
if (team) { if (team) {
// Use the exact name as stored in the database
setName(team.name); setName(team.name);
} }
} catch (err) { } catch (err) {
@ -410,6 +433,7 @@ const TeamForm = ({ isEdit = false }) => {
setSubmitting(true); setSubmitting(true);
try { try {
// Send the name exactly as entered by the user without any transformation
if (isEdit) { if (isEdit) {
await apiService.updateTeam(id, { name }, token); await apiService.updateTeam(id, { name }, token);
} else { } else {
@ -434,7 +458,9 @@ const TeamForm = ({ isEdit = false }) => {
value={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
required required
placeholder="Enter team name exactly as desired"
/> />
<small className="form-text">Name will be saved exactly as entered</small>
</div> </div>
<button <button
type="submit" type="submit"
@ -457,8 +483,8 @@ const ResultCalendar = () => {
const [error, setError] = useState(''); const [error, setError] = useState('');
const { token } = React.useContext(AuthContext); const { token } = React.useContext(AuthContext);
useEffect(() => {
const fetchData = async () => { const fetchData = async () => {
setLoading(true);
try { try {
const [teamsData, resultsData] = await Promise.all([ const [teamsData, resultsData] = await Promise.all([
apiService.getTeams(token), apiService.getTeams(token),
@ -466,13 +492,16 @@ const ResultCalendar = () => {
]); ]);
setTeams(teamsData); setTeams(teamsData);
setResults(resultsData); setResults(resultsData);
setError('');
setLoading(false); setLoading(false);
} catch (err) { } catch (err) {
console.error("Error fetching data:", err);
setError('Failed to fetch data'); setError('Failed to fetch data');
setLoading(false); setLoading(false);
} }
}; };
useEffect(() => {
fetchData(); fetchData();
}, [date, token]); }, [date, token]);
@ -481,22 +510,28 @@ const ResultCalendar = () => {
}; };
const handleDeleteResult = async (id) => { const handleDeleteResult = async (id) => {
// First, ensure the ID is valid
if (!id) {
console.error("Invalid result ID:", id);
setError("Cannot delete result: Invalid ID");
return;
}
console.log("Attempting to delete result with ID:", id);
if (window.confirm('Are you sure you want to delete this result?')) { if (window.confirm('Are you sure you want to delete this result?')) {
try { try {
await apiService.deleteResult(id, token); await apiService.deleteResult(id, token);
setResults(results.filter(result => result.id !== id)); // Refresh the results after deletion
fetchData();
} catch (err) { } catch (err) {
setError('Failed to delete result'); console.error("Error deleting result:", err);
setError(`Failed to delete result: ${err.message}`);
} }
} }
}; };
if (loading) return <div>Loading...</div>; if (loading) return <div>Loading...</div>;
if (error) return <div className="error"><div>
<Link to={`/results/new`} className="btn-primary">Add New Result</Link>
</div>
{error}
</div>;
return ( return (
<div className="calendar-container"> <div className="calendar-container">
@ -514,6 +549,8 @@ const ResultCalendar = () => {
<h3>Results for {date}</h3> <h3>Results for {date}</h3>
<Link to={`/results/new?date=${date}`} className="btn-primary">Add New Result</Link> <Link to={`/results/new?date=${date}`} className="btn-primary">Add New Result</Link>
{error && <div className="error">{error}</div>}
{results.length === 0 ? ( {results.length === 0 ? (
<p>No results for this date.</p> <p>No results for this date.</p>
) : ( ) : (
@ -530,12 +567,12 @@ const ResultCalendar = () => {
{results.map(result => ( {results.map(result => (
<tr key={result.id}> <tr key={result.id}>
<td>{result.team}</td> <td>{result.team}</td>
<td>{result.visible_result}</td> <td>{result.visible_result || result.result}</td>
<td>{new Date(result.result_time).toISOString().split('T').join(" ").replace("Z", "").slice(0, -4)}</td> <td>{new Date(result.result_time).toISOString().split('T').join(" ").replace("Z", "").slice(0, -4)}</td>
<td> <td>
<Link to={`/admin/results/edit/${result.id}?date=${date}`} className="btn-secondary">Edit</Link> <Link to={`/admin/results/edit/${result.id}?date=${date}`} className="btn-secondary">Edit</Link>
<button <button
onClick={() => handleDeleteResult(result.id)} onClick={() => handleDeleteResult(`${result.id}`)}
className="btn-danger" className="btn-danger"
> >
Delete Delete
@ -551,12 +588,13 @@ const ResultCalendar = () => {
); );
}; };
// result form to update result
const ResultForm = ({ isEdit = false }) => { const ResultForm = ({ isEdit = false }) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
team: '', team: '',
result: '', result: '',
date: new Date().toISOString().split('T')[0], date: new Date().toISOString().split('T')[0],
announcement_time: '12:00:00' result_time: '12:00:00' // Default now includes seconds
}); });
const [teams, setTeams] = useState([]); const [teams, setTeams] = useState([]);
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
@ -584,10 +622,17 @@ const ResultForm = ({ isEdit = false }) => {
const results = await apiService.getDailyResults(dateParam || formData.date, token); const results = await apiService.getDailyResults(dateParam || formData.date, token);
const result = results.find(r => r.id === parseInt(id)); const result = results.find(r => r.id === parseInt(id));
if (result) { if (result) {
// Extract time from result_time and ensure it has seconds
const resultTime = result.result_time.split(' ')[1];
const formattedTime = resultTime.includes('.')
? resultTime.split('.')[0]
: resultTime.length === 5 ? `${resultTime}:00` : resultTime;
setFormData({ setFormData({
team: result.team_id.toString(), team: result.team, // Use the exact team name as stored
result: result.visible_result, result: result.visible_result,
result_time: result.result_time date: result.result_time.split(' ')[0],
result_time: formattedTime
}); });
} }
} }
@ -610,9 +655,9 @@ const ResultForm = ({ isEdit = false }) => {
try { try {
const payload = { const payload = {
team: formData.team, // This should be the team ID team: formData.team, // Use the exact team name as selected
result: formData.result, result: formData.result,
result_time: formData.date + " " + formData.result_time result_time: `${formData.date} ${formData.result_time}`
}; };
if (isEdit) { if (isEdit) {
@ -643,7 +688,7 @@ const ResultForm = ({ isEdit = false }) => {
> >
<option value="">Select a team</option> <option value="">Select a team</option>
{teams.map(team => ( {teams.map(team => (
<option key={team.name} value={team.name}>{team.name}</option> <option key={team.id} value={team.name}>{team.name}</option>
))} ))}
</select> </select>
</div> </div>
@ -669,12 +714,13 @@ const ResultForm = ({ isEdit = false }) => {
/> />
</div> </div>
<div className="form-group"> <div className="form-group">
<label>Result Time</label> <label>Result Time (HH:MM:SS)</label>
<input <input
type="time" type="time"
name="result_time" name="result_time"
value={formData.result_time} value={formData.result_time}
onChange={handleChange} onChange={handleChange}
step="1" // Enable seconds in the time picker
required required
/> />
</div> </div>
@ -690,7 +736,6 @@ const ResultForm = ({ isEdit = false }) => {
</div> </div>
); );
}; };
// Scheduled Games Components // Scheduled Games Components
const ScheduleCalendar = () => { const ScheduleCalendar = () => {
const [date, setDate] = useState(new Date().toISOString().split('T')[0]); const [date, setDate] = useState(new Date().toISOString().split('T')[0]);
@ -787,12 +832,13 @@ const ScheduleCalendar = () => {
); );
}; };
// ScheduleForm component with seconds support
const ScheduleForm = ({ isEdit = false }) => { const ScheduleForm = ({ isEdit = false }) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
home_team: '', home_team: '',
away_team: '', away_team: '',
game_date: new Date().toISOString().split('T')[0], game_date: new Date().toISOString().split('T')[0],
game_time: '12:00:00', game_time: '12:00:00', // Default now includes seconds
status: 'SCHEDULED' status: 'SCHEDULED'
}); });
const [teams, setTeams] = useState([]); const [teams, setTeams] = useState([]);
@ -821,11 +867,15 @@ const ScheduleForm = ({ isEdit = false }) => {
const games = await apiService.getScheduledGames(dateParam || formData.game_date, token); const games = await apiService.getScheduledGames(dateParam || formData.game_date, token);
const game = games.find(g => g.id === parseInt(id)); const game = games.find(g => g.id === parseInt(id));
if (game) { if (game) {
// Ensure game_time includes seconds
const gameTime = game.game_time;
const formattedTime = gameTime.length === 5 ? `${gameTime}:00` : gameTime;
setFormData({ setFormData({
home_team: game.home_team_id.toString(), home_team: game.home_team_id.toString(),
away_team: game.away_team_id.toString(), away_team: game.away_team_id.toString(),
game_date: game.game_date, game_date: game.game_date,
game_time: game.game_time, game_time: formattedTime,
status: game.status status: game.status
}); });
} }
@ -848,10 +898,16 @@ const ScheduleForm = ({ isEdit = false }) => {
setSubmitting(true); setSubmitting(true);
try { try {
const payload = {
...formData,
// Ensure the API receives the complete time with seconds
game_time: formData.game_time.length === 5 ? `${formData.game_time}:00` : formData.game_time
};
if (isEdit) { if (isEdit) {
await apiService.updateScheduledGame(id, formData, token); await apiService.updateScheduledGame(id, payload, token);
} else { } else {
await apiService.createScheduledGame(formData, token); await apiService.createScheduledGame(payload, token);
} }
navigate(`/admin/schedule?date=${formData.game_date}`); navigate(`/admin/schedule?date=${formData.game_date}`);
} catch (err) { } catch (err) {
@ -904,12 +960,13 @@ const ScheduleForm = ({ isEdit = false }) => {
/> />
</div> </div>
<div className="form-group"> <div className="form-group">
<label>Time</label> <label>Time (HH:MM:SS)</label>
<input <input
type="time" type="time"
name="game_time" name="game_time"
value={formData.game_time} value={formData.game_time}
onChange={handleChange} onChange={handleChange}
step="1" // Enable seconds in the time picker
required required
/> />
</div> </div>
@ -1001,7 +1058,8 @@ const App = () => {
</ProtectedRoute> </ProtectedRoute>
} }
/> />
<Route path="/" element={<Home />} /> <Route path="/" element={<Home2 />} />
<Route path="/results" element={<GameList />} />
<Route path="/res" element={<TeamResults />} /> <Route path="/res" element={<TeamResults />} />
</Routes> </Routes>
</AuthProvider> </AuthProvider>

640
src/pages/GameList.js Normal file
View File

@ -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 (
<div className="bg-gray-200 min-h-screen">
<div className="max-w-6xl mx-auto p-4">
{error && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
<p>{error}</p>
</div>
)}
<Today/>
<div className="bg-red-600 p-4 text-white text-center text-xl font-bold rounded-t-lg shadow-lg">
Satta Result of {dates.length > 1 && formatDate(dates[1])} & {dates.length > 0 && formatDate(dates[0])}
</div>
{/* Controls */}
<div className="bg-white p-4 mb-4 flex flex-col md:flex-row justify-between items-center shadow-md">
<div className="text-lg font-semibold text-gray-800 mb-2 md:mb-0">Latest Results</div>
<div className="flex gap-2">
<button
className="bg-black text-white px-4 py-2 rounded flex items-center gap-2 hover:bg-gray-800 transition"
onClick={handleCalendarView}
disabled={loading}
>
<Calendar size={16} />
Calendar View
</button>
<button
className="bg-red-600 text-white px-4 py-2 rounded flex items-center gap-2 hover:bg-red-700 transition"
onClick={handleRefresh}
disabled={loading}
>
<RefreshCw size={16} />
Refresh
</button>
</div>
</div>
{/* Loading indicator */}
{loading && (
<div className="bg-white p-8 mb-4 rounded shadow flex justify-center items-center">
<div className="flex items-center gap-2">
<RefreshCw size={24} className="animate-spin text-red-600" />
<span>Loading data...</span>
</div>
</div>
)}
{/* Upcoming Matches */}
{!loading && upcomingMatches.length > 0 && !showChartView && !showCalendar && (
<div className="bg-white p-4 mb-4 rounded shadow">
<h2 className="text-lg font-semibold mb-4 flex items-center gap-2 text-red-600">
<Clock size={20} />
Upcoming Matches Today
</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-black text-white">
<th className="border border-gray-300 p-2 text-left">Team</th>
<th className="border border-gray-300 p-2 text-center">Scheduled Time</th>
</tr>
</thead>
<tbody>
{upcomingMatches.map((match, index) => (
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
<td className="border border-gray-300 p-2 font-medium">{match.team}</td>
<td className="border border-gray-300 p-2 text-center">{formatTime(match.result_time)}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Chart View */}
{!loading && showChartView && selectedTeam && (
<div className="bg-white p-4 mb-4 rounded shadow">
<h2 className="text-lg font-semibold mb-4 text-red-600">Monthly Chart: {selectedTeam.name}</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-black text-white">
<th className="border border-gray-300 p-2 text-left">Date</th>
<th className="border border-gray-300 p-2 text-center">Time</th>
<th className="border border-gray-300 p-2 text-right">Result</th>
</tr>
</thead>
<tbody>
{selectedTeam.chartData && selectedTeam.chartData.map((item, index) => (
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
<td className="border border-gray-300 p-2">{new Date(item.result_date).toLocaleDateString()}</td>
<td className="border border-gray-300 p-2 text-center">{formatTime(item.result_time)}</td>
<td className="border border-gray-300 p-2 text-right font-bold">{item.result}</td>
</tr>
))}
{(!selectedTeam.chartData || selectedTeam.chartData.length === 0) && (
<tr>
<td colSpan="3" className="border border-gray-300 p-2 text-center">No chart data available</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="mt-4 flex justify-end">
<button
className="bg-black text-white px-4 py-2 rounded hover:bg-gray-800 transition"
onClick={() => setShowChartView(false)}
>
Back to Results
</button>
</div>
</div>
)}
{/* Calendar View - Improved Responsive Design */}
{!loading && showCalendar && (
<div className="bg-white p-4 mb-4 rounded shadow">
<div className="flex justify-between items-center mb-4">
<button
className="bg-black text-white p-2 rounded flex items-center gap-1 hover:bg-gray-800 transition"
onClick={() => handleMonthChange(-1)}
>
<ChevronLeft size={16} />
<span className="hidden sm:inline">Previous</span>
</button>
<h2 className="text-lg font-semibold text-red-600">
{currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
</h2>
<button
className="bg-black text-white p-2 rounded flex items-center gap-1 hover:bg-gray-800 transition"
onClick={() => handleMonthChange(1)}
>
<span className="hidden sm:inline">Next</span>
<ChevronRight size={16} />
</button>
</div>
<div className="grid grid-cols-7 gap-1 mb-2">
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => (
<div key={day} className="text-center font-semibold bg-gray-800 text-white p-1 text-xs sm:text-sm">{day}</div>
))}
</div>
<div className="grid grid-cols-7 gap-1">
{calendarData.map((day, index) => (
<div
key={index}
className={`border rounded p-1 overflow-y-auto ${day ? 'bg-white' : 'bg-gray-100'
}`}
style={{
height: "120px",
maxHeight: "120px"
}}
>
{day && (
<>
<div className={`text-right text-sm font-medium ${new Date().toISOString().split('T')[0] === day.date ?
'bg-red-600 text-white p-1 rounded-full w-6 h-6 flex items-center justify-center ml-auto' :
'text-gray-700'
}`}>
{day.day}
</div>
<div className="overflow-y-auto" style={{ maxHeight: "90px" }}>
{day.results.length > 0 ? (
day.results.map((teamResult, i) => (
<div key={i} className="mt-1 border-t border-gray-200 pt-1">
<div className="font-semibold text-xs text-red-600">{teamResult.team}</div>
{teamResult.results.map((r, j) => (
<div key={j} className="text-xs flex justify-between">
<span className="text-gray-500">{r.time}</span>
<span className="font-bold">{r.result}</span>
</div>
))}
</div>
))
) : (
<div className="text-xs text-gray-400 mt-2 text-center">No results</div>
)}
</div>
</>
)}
</div>
))}
</div>
<div className="mt-4 flex justify-end">
<button
className="bg-black text-white px-4 py-2 rounded hover:bg-gray-800 transition"
onClick={() => setShowCalendar(false)}
>
Back to Results
</button>
</div>
</div>
)}
{/* Teams Table with multiple results support */}
{!loading && !showCalendar && !showChartView && (
<div className="bg-white rounded-b-lg overflow-hidden shadow-lg">
<table className="w-full border-collapse">
<thead>
<tr className="bg-black text-white">
<th className="p-3 text-left">Games List</th>
<th className="p-3 text-center">
{dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 0 && new Date(dates[0]).getDate()}th
</th>
<th className="p-3 text-center">
{dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 1 && new Date(dates[1]).getDate()}th
</th>
<th className="p-3 text-center">Chart</th>
</tr>
</thead>
<tbody>
{teams.map(team => (
<tr key={team.id} className="border-b hover:bg-gray-50">
<td className="p-3">
<div className="font-semibold text-red-600">{team.name}</div>
<div className="text-sm text-gray-500">at {team.time}</div>
<div className="text-xs text-black underline mt-1 cursor-pointer hover:text-red-600" onClick={() => handleViewChart(team)}>Record Chart</div>
</td>
<td className="p-3 text-center">
{dates.length > 0 && team.results[dates[0]] && team.results[dates[0]].length > 0 ? (
<div className="flex flex-col gap-1">
{team.results[dates[0]].map((result, idx) => (
<div key={idx} className="flex flex-col">
<span className="text-2xl font-bold">{result.result}</span>
<span className="text-xs text-gray-500">{result.time}</span>
</div>
))}
</div>
) : (
<span className="text-2xl font-bold text-gray-400">XX</span>
)}
</td>
<td className="p-3 text-center">
{dates.length > 1 && team.results[dates[1]] && team.results[dates[1]].length > 0 ? (
<div className="flex flex-col gap-1">
{team.results[dates[1]].map((result, idx) => (
<div key={idx} className="flex flex-col">
<span className="text-2xl font-bold">{result.result}</span>
<span className="text-xs text-gray-500">{result.time}</span>
</div>
))}
</div>
) : (
<span className="text-2xl font-bold text-gray-400">XX</span>
)}
</td>
<td className="p-3">
<div className="flex justify-center">
<button
className="p-2 bg-red-100 text-red-600 rounded hover:bg-red-200 transition"
onClick={() => handleViewChart(team)}
title="View Monthly Chart"
>
<BarChart2 size={16} />
</button>
</div>
</td>
</tr>
))}
{teams.length === 0 && (
<tr>
<td colSpan="4" className="p-4 text-center">No teams found</td>
</tr>
)}
</tbody>
</table>
<div className="bg-black text-white text-center p-3">
<button className="hover:text-red-400 transition" onClick={handleCalendarView}>Click here for all games results.</button>
</div>
</div>
)}
</div>
<div className="w-full bg-white text-black">
{/* FAQ Section */}
<div className="max-w-6xl mx-auto py-6">
{faqs.map((faq, index) => (
<div key={index} className="mb-2">
<button
className="w-full bg-red-600 text-white text-lg font-semibold py-3 px-4 flex justify-between items-center rounded-md"
onClick={() => toggleFAQ(index)}
>
{faq.question}
<span>{openIndex === index ? "▲" : "▼"}</span>
</button>
{openIndex === index && (
<div className="p-4 bg-gray-100 border border-gray-300">
{faq.answer}
</div>
)}
</div>
))}
</div>
{/* Footer Section */}
<footer className="bg-white border-t py-6 text-center">
<div className="max-w-3xl mx-auto text-gray-600 text-sm">
<p className="font-bold text-xl text-black flex items-center justify-center">
MATKA <span className="text-red-600"> SATTA</span>
</p>
<p className="mt-2">
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.
</p>
<p className="mt-2">
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.
</p>
<p className="mt-4 flex justify-center space-x-4 text-black font-semibold">
<span>Media Center</span>
<span>Legal</span>
<span>Privacy</span>
<span>español</span>
</p>
</div>
</footer>
</div>
</div>
);
};
export default GameList;

View File

@ -1,6 +1,7 @@
import React, { useState, useEffect } from 'react'; 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 axios from 'axios';
import TodaysMatch from './TodaysMatch';
const Home2 = () => { const Home2 = () => {
const [teams, setTeams] = useState([]); const [teams, setTeams] = useState([]);
@ -13,23 +14,45 @@ const Home2 = () => {
const [error, setError] = useState(null); const [error, setError] = useState(null);
const [calendarData, setCalendarData] = useState([]); const [calendarData, setCalendarData] = useState([]);
const [currentMonth, setCurrentMonth] = useState(new Date()); const [currentMonth, setCurrentMonth] = useState(new Date());
const [upcomingMatches, setUpcomingMatches] = useState([]);
// API URL // API URL
const API_URL = 'http://localhost:5500/api'; 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 // Fetch teams data
useEffect(() => { useEffect(() => {
const fetchData = async () => {
const fetchTeams = async () => {
try { try {
setLoading(true); setLoading(true);
// Get all teams // Get all teams
const teamsResponse = await axios.get(`${API_URL}/teams`); const teamsResponse = await axios.get(`${API_URL}/teams`);
alert("teamsResponse");
// Get today's date and format it // Get today's date and format it
const today = new Date(); const today = new Date();
const todayFormatted = today.toISOString().split('T')[0]; const todayFormatted = today.toISOString().split('T')[0];
// Get yesterday's date and format it // Get yesterday's date and format it
const yesterday = new Date(); const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1); yesterday.setDate(yesterday.getDate() - 1);
@ -39,44 +62,54 @@ const Home2 = () => {
setDates([yesterdayFormatted, todayFormatted]); setDates([yesterdayFormatted, todayFormatted]);
// Get today's results // Get today's results
const todayResultsResponse = await axios.get(`${API_URL}/today`); const todayResultsResponse = await axios.get(`${API_URL}/results/daily?date=${todayFormatted}`);
const todayResults = todayResultsResponse.data;
// Get yesterday's results for each team // Get yesterday's results
const yesterdayResultsPromises = teamsResponse.data.map(team => const yesterdayResultsResponse = await axios.get(`${API_URL}/results/daily?date=${yesterdayFormatted}`);
axios.get(`${API_URL}/results?team=${team.name}&date=${yesterdayFormatted}`) const yesterdayResults = yesterdayResultsResponse.data;
.then(response => response.data)
.catch(() => null) // If no result, return null
);
const yesterdayResults = await Promise.all(yesterdayResultsPromises); // Process upcoming matches
const upcoming = todayResults.filter(result => isUpcoming(result.result_time));
setUpcomingMatches(upcoming);
// Combine team data with results // Combine team data with results
const teamsWithResults = teamsResponse.data.map((team, index) => { const teamsWithResults = teamsResponse.data.map(team => {
const results = {}; // Get all results for this team
const yesterdayTeamResults = yesterdayResults.filter(r => r.team === team.name);
const todayTeamResults = todayResults.filter(r => r.team === team.name);
// Add yesterday's result if available // Create result arrays for both days
if (yesterdayResults[index]) { const yesterdayResultsArr = yesterdayTeamResults.map(r => ({
results[yesterdayFormatted] = yesterdayResults[index].result; result: r.visible_result,
} time: formatTime(r.result_time)
}));
// Add today's result if available const todayResultsArr = todayTeamResults
const todayResult = todayResultsResponse.data.find(r => r.team === team.name); .filter(r => !isUpcoming(r.result_time))
if (todayResult) { .map(r => ({
results[todayFormatted] = todayresult.visible_result; result: r.visible_result,
} time: formatTime(r.result_time)
}));
// Extract time from team name or use default // Extract latest scheduled time
let time = "XX:XX"; let latestTime = "XX:XX";
const timePart = team.name.match(/\d{2}:\d{2}\s*(?:AM|PM)/i); const latestTodayResult = todayTeamResults
if (timePart) { .sort((a, b) => new Date(b.result_time) - new Date(a.result_time))
time = timePart[0]; .find(r => r.result_time);
if (latestTodayResult) {
latestTime = formatTime(latestTodayResult.result_time);
} }
return { return {
id: team.id, id: team.id,
name: team.name, name: team.name,
time: time, time: latestTime,
results: results results: {
[yesterdayFormatted]: yesterdayResultsArr,
[todayFormatted]: todayResultsArr
}
}; };
}); });
@ -89,7 +122,7 @@ const Home2 = () => {
} }
}; };
fetchTeams(); fetchData();
// Update current time every minute // Update current time every minute
const interval = setInterval(() => { const interval = setInterval(() => {
@ -183,18 +216,33 @@ const Home2 = () => {
const dateStr = dateObj.toISOString().split('T')[0]; const dateStr = dateObj.toISOString().split('T')[0];
const dayData = allResults.find(r => r.date === dateStr); const dayData = allResults.find(r => r.date === dateStr);
let teamResults = {}; let dayResults = [];
if (dayData && dayData.results.length > 0) { if (dayData && dayData.results.length > 0) {
// Group by team
const teamResults = {};
dayData.results.forEach(result => { 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({ calendarDays.push({
day: i, day: i,
date: dateStr, date: dateStr,
results: teamResults results: dayResults
}); });
} }
@ -229,243 +277,128 @@ const Home2 = () => {
window.location.reload(); 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 ( return (
<div className="bg-gray-100 min-h-screen p-4"> <div className="bg-gray-200 min-h-screen">
<div className="w-full bg-gray-100 p-4 text-center"> <div className="w-full bg-white p-4 text-center text-white">
{/* Header */} {/* Header */}
<h1 className="text-3xl font-bold text-black uppercase">SATTA-KING-FAST.com</h1> <h1 className="text-3xl md:text-4xl font-bold uppercase text-red-600">
<img
src="./logo.PNG"
alt="Advertisement"
className="w-28 h-30 m-auto"
/>
</h1>
{/* Advertisement Banner */} {/* Advertisement Banner */}
<div className="mt-4 flex justify-center items-center"> <div className="mt-4 flex justify-center items- border w-full lg:w-3/4 m-auto">
<img <img
src="/api/placeholder/800/120" src="./add.png"
alt="Advertisement" alt="Advertisement"
className="w-full max-w-4xl" className="w-auto max-w-4xl h-14"
/> />
</div> </div>
{/* Informational Text */} {/* Informational Text */}
<p className="mt-4 text-gray-700 text-sm p-1 w-full lg:w-3/4 m-auto"> <p className="mt-4 text-black text-sm p-1 w-full lg:w-3/4 m-auto">
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.
</p> </p>
{/* Disclaimer */} {/* Disclaimer */}
<p className="mt-2 text-blue-600 text-sm font-medium bg-white p-1 w-full lg:w-3/4 m-auto"> <p className="mt-2 text-red-400 text-sm font-medium bg-gray-900 p-2 rounded w-full lg:w-3/4 m-auto">
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.
</p> </p>
{/* Warning Message */} {/* Warning Message */}
<p className="mt-2 text-red-600 font-bold bg-white p-1 w-full lg:w-3/4 m-auto"> <p className="mt-2 text-white font-bold bg-red-700 p-2 rounded w-full lg:w-3/4 m-auto">
पय , पर ि , पहल - धनयव पय , पर ि , पहल - धनयव
</p> </p>
{/* Contact Link */} {/* Contact Link */}
<p className="mt-2 text-green-600 font-medium bg-white p-1 w-full lg:w-3/4 m-auto"> <p className="mt-2 text-white font-medium bg-gray-800 p-2 rounded w-full lg:w-3/4 m-auto">
हमस पर करन ि <a href="#" className="underline">यह ि कर</a> हमस पर करन ि <a href="#" className="underline text-red-400 hover:text-red-300">यह ि कर</a>
</p> </p>
{/* Timestamp */} {/* Timestamp */}
<p className="mt-2 text-gray-600 text-xs"> <p className="mt-2 text-red-400 text-lg text-bold">
Updated: {currentTime} IST. Updated: {currentTime} IST.
</p> </p>
</div> </div>
<div className="max-w-6xl mx-auto p-4">
<div className="max-w-6xl mx-auto"> <TodaysMatch />
{error && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
<p>{error}</p>
</div>
)}
<div className="bg-emerald-400 p-4 text-white text-center text-xl font-bold rounded-t-lg">
{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' })}
</div> </div>
{/* Controls */}
<div className="bg-white p-4 mb-4 flex justify-between items-center">
<div className="text-lg font-semibold">Latest Results</div>
<div className="flex gap-2">
<div className="w-full bg-white text-black">
{/* FAQ Section */}
<div className="max-w-6xl mx-auto py-6">
{faqs.map((faq, index) => (
<div key={index} className="mb-2">
<button <button
className="bg-blue-500 text-white px-4 py-2 rounded flex items-center gap-2" className="w-full bg-red-600 text-white text-lg font-semibold py-3 px-4 flex justify-between items-center rounded-md"
onClick={handleCalendarView} onClick={() => toggleFAQ(index)}
disabled={loading}
> >
<Calendar size={16} /> {faq.question}
Calendar View <span>{openIndex === index ? "▲" : "▼"}</span>
</button>
<button
className="bg-green-500 text-white px-4 py-2 rounded flex items-center gap-2"
onClick={handleRefresh}
disabled={loading}
>
<RefreshCw size={16} />
Refresh
</button> </button>
{openIndex === index && (
<div className="p-4 bg-gray-100 border border-gray-300">
{faq.answer}
</div> </div>
</div>
{/* Loading indicator */}
{loading && (
<div className="bg-white p-8 mb-4 rounded shadow flex justify-center items-center">
<div className="flex items-center gap-2">
<RefreshCw size={24} className="animate-spin text-blue-500" />
<span>Loading data...</span>
</div>
</div>
)}
{/* Chart View */}
{!loading && showChartView && selectedTeam && (
<div className="bg-white p-4 mb-4 rounded shadow">
<h2 className="text-lg font-semibold mb-4">Monthly Chart: {selectedTeam.name}</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-100">
<th className="border p-2 text-left">Date</th>
<th className="border p-2 text-right">Result</th>
</tr>
</thead>
<tbody>
{selectedTeam.chartData && selectedTeam.chartData.map((item, index) => (
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
<td className="border p-2">{new Date(item.result_date).toLocaleDateString()}</td>
<td className="border p-2 text-right font-bold">{item.result}</td>
</tr>
))}
{(!selectedTeam.chartData || selectedTeam.chartData.length === 0) && (
<tr>
<td colSpan="2" className="border p-2 text-center">No chart data available</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="mt-4 flex justify-end">
<button
className="bg-gray-300 px-4 py-2 rounded"
onClick={() => setShowChartView(false)}
>
Back to Results
</button>
</div>
</div>
)}
{/* Calendar View */}
{!loading && showCalendar && (
<div className="bg-white p-4 mb-4 rounded shadow">
<div className="flex justify-between items-center mb-4">
<button
className="bg-gray-200 p-2 rounded"
onClick={() => handleMonthChange(-1)}
>
Previous Month
</button>
<h2 className="text-lg font-semibold">
{currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
</h2>
<button
className="bg-gray-200 p-2 rounded"
onClick={() => handleMonthChange(1)}
>
Next Month
</button>
</div>
<div className="grid grid-cols-7 gap-2 mb-2">
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => (
<div key={day} className="text-center font-semibold">{day}</div>
))}
</div>
<div className="grid grid-cols-7 gap-2">
{calendarData.map((day, index) => (
<div key={index} className={`border rounded p-2 min-h-16 ${day ? 'bg-white' : ''}`}>
{day && (
<>
<div className="text-right text-sm text-gray-500">{day.day}</div>
{teams.map(team => (
<div key={team.id} className="text-xs mt-1">
{day.results[team.name] && (
<>
<span className="font-semibold">{team.name.split(' ')[0]}:</span> {day.results[team.name]}
</>
)}
</div>
))}
</>
)} )}
</div> </div>
))} ))}
</div> </div>
<div className="mt-4 flex justify-end"> {/* Footer Section */}
<button <footer className="bg-white border-t py-6 text-center">
className="bg-gray-300 px-4 py-2 rounded" <div className="max-w-3xl mx-auto text-gray-600 text-sm">
onClick={() => setShowCalendar(false)} <p className="font-bold text-xl text-black flex items-center justify-center">
> MATKA <span className="text-red-600"> SATTA</span>
Back to Results </p>
</button> <p className="mt-2">
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.
</p>
<p className="mt-2">
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.
</p>
<p className="mt-4 flex justify-center space-x-4 text-black font-semibold">
<span>Media Center</span>
<span>Legal</span>
<span>Privacy</span>
<span>español</span>
</p>
</div> </div>
</div> </footer>
)}
{/* Teams Table */}
{!loading && !showCalendar && !showChartView && (
<div className="bg-white rounded-b-lg overflow-hidden">
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-800 text-white">
<th className="p-3 text-left">Games List</th>
<th className="p-3 text-center">
{dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 0 && new Date(dates[0]).getDate()}th
</th>
<th className="p-3 text-center">
{dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 1 && new Date(dates[1]).getDate()}th
</th>
<th className="p-3 text-center">Chart</th>
</tr>
</thead>
<tbody>
{teams.map(team => (
<tr key={team.id} className="border-b hover:bg-gray-50">
<td className="p-3">
<div className="font-semibold">{team.name}</div>
<div className="text-sm text-gray-500">at {team.time}</div>
<div className="text-xs text-blue-500 underline mt-1 cursor-pointer" onClick={() => handleViewChart(team)}>Record Chart</div>
</td>
<td className="p-3 text-center text-2xl font-bold">{dates.length > 0 && team.results[dates[0]] || 'XX'}</td>
<td className="p-3 text-center text-2xl font-bold">{dates.length > 1 && team.results[dates[1]] || 'XX'}</td>
<td className="p-3">
<div className="flex justify-center">
<button
className="p-2 bg-green-100 text-green-600 rounded"
onClick={() => handleViewChart(team)}
title="View Monthly Chart"
>
<BarChart2 size={16} />
</button>
</div>
</td>
</tr>
))}
{teams.length === 0 && (
<tr>
<td colSpan="4" className="p-4 text-center">No teams found</td>
</tr>
)}
</tbody>
</table>
<div className="bg-gray-700 text-white text-center p-3">
<button className="hover:underline" onClick={handleCalendarView}>Click here for all games results.</button>
</div>
</div>
)}
</div> </div>
</div> </div>
); );

682
src/pages/Home3.js Normal file
View File

@ -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 (
<div className="bg-gray-200 min-h-screen">
<div className="w-full bg-white p-4 text-center text-white">
{/* Header */}
<h1 className="text-3xl md:text-4xl font-bold uppercase text-red-600">
<img
src="./logo.PNG"
alt="Advertisement"
className="w-28 h-30 m-auto"
/>
</h1>
{/* Advertisement Banner */}
<div className="mt-4 flex justify-center items- border">
<img
src="./add.png"
alt="Advertisement"
className="w-auto max-w-4xl h-14"
/>
</div>
{/* Informational Text */}
<p className="mt-4 text-black text-sm p-1 w-full lg:w-3/4 m-auto">
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.
</p>
{/* Disclaimer */}
<p className="mt-2 text-red-400 text-sm font-medium bg-gray-900 p-2 rounded w-full lg:w-3/4 m-auto">
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.
</p>
{/* Warning Message */}
<p className="mt-2 text-white font-bold bg-red-700 p-2 rounded w-full lg:w-3/4 m-auto">
पय , पर ि , पहल - धनयव
</p>
{/* Contact Link */}
<p className="mt-2 text-white font-medium bg-gray-800 p-2 rounded w-full lg:w-3/4 m-auto">
हमस पर करन ि <a href="#" className="underline text-red-400 hover:text-red-300">यह ि कर</a>
</p>
{/* Timestamp */}
<p className="mt-2 text-red-400 text-lg text-bold">
Updated: {currentTime} IST.
</p>
</div>
<div className="max-w-6xl mx-auto p-4">
{error && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
<p>{error}</p>
</div>
)}
<TodaysMatch/>
<div className="bg-red-600 p-4 text-white text-center text-xl font-bold rounded-t-lg shadow-lg">
Satta Result of {dates.length > 1 && formatDate(dates[1])} & {dates.length > 0 && formatDate(dates[0])}
</div>
{/* Controls */}
<div className="bg-white p-4 mb-4 flex flex-col md:flex-row justify-between items-center shadow-md">
<div className="text-lg font-semibold text-gray-800 mb-2 md:mb-0">Latest Results</div>
<div className="flex gap-2">
<button
className="bg-black text-white px-4 py-2 rounded flex items-center gap-2 hover:bg-gray-800 transition"
onClick={handleCalendarView}
disabled={loading}
>
<Calendar size={16} />
Calendar View
</button>
<button
className="bg-red-600 text-white px-4 py-2 rounded flex items-center gap-2 hover:bg-red-700 transition"
onClick={handleRefresh}
disabled={loading}
>
<RefreshCw size={16} />
Refresh
</button>
</div>
</div>
{/* Loading indicator */}
{loading && (
<div className="bg-white p-8 mb-4 rounded shadow flex justify-center items-center">
<div className="flex items-center gap-2">
<RefreshCw size={24} className="animate-spin text-red-600" />
<span>Loading data...</span>
</div>
</div>
)}
{/* Upcoming Matches */}
{!loading && upcomingMatches.length > 0 && !showChartView && !showCalendar && (
<div className="bg-white p-4 mb-4 rounded shadow">
<h2 className="text-lg font-semibold mb-4 flex items-center gap-2 text-red-600">
<Clock size={20} />
Upcoming Matches Today
</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-black text-white">
<th className="border border-gray-300 p-2 text-left">Team</th>
<th className="border border-gray-300 p-2 text-center">Scheduled Time</th>
</tr>
</thead>
<tbody>
{upcomingMatches.map((match, index) => (
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
<td className="border border-gray-300 p-2 font-medium">{match.team}</td>
<td className="border border-gray-300 p-2 text-center">{formatTime(match.result_time)}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Chart View */}
{!loading && showChartView && selectedTeam && (
<div className="bg-white p-4 mb-4 rounded shadow">
<h2 className="text-lg font-semibold mb-4 text-red-600">Monthly Chart: {selectedTeam.name}</h2>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-black text-white">
<th className="border border-gray-300 p-2 text-left">Date</th>
<th className="border border-gray-300 p-2 text-center">Time</th>
<th className="border border-gray-300 p-2 text-right">Result</th>
</tr>
</thead>
<tbody>
{selectedTeam.chartData && selectedTeam.chartData.map((item, index) => (
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
<td className="border border-gray-300 p-2">{new Date(item.result_date).toLocaleDateString()}</td>
<td className="border border-gray-300 p-2 text-center">{formatTime(item.result_time)}</td>
<td className="border border-gray-300 p-2 text-right font-bold">{item.result}</td>
</tr>
))}
{(!selectedTeam.chartData || selectedTeam.chartData.length === 0) && (
<tr>
<td colSpan="3" className="border border-gray-300 p-2 text-center">No chart data available</td>
</tr>
)}
</tbody>
</table>
</div>
<div className="mt-4 flex justify-end">
<button
className="bg-black text-white px-4 py-2 rounded hover:bg-gray-800 transition"
onClick={() => setShowChartView(false)}
>
Back to Results
</button>
</div>
</div>
)}
{/* Calendar View - Improved Responsive Design */}
{!loading && showCalendar && (
<div className="bg-white p-4 mb-4 rounded shadow">
<div className="flex justify-between items-center mb-4">
<button
className="bg-black text-white p-2 rounded flex items-center gap-1 hover:bg-gray-800 transition"
onClick={() => handleMonthChange(-1)}
>
<ChevronLeft size={16} />
<span className="hidden sm:inline">Previous</span>
</button>
<h2 className="text-lg font-semibold text-red-600">
{currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
</h2>
<button
className="bg-black text-white p-2 rounded flex items-center gap-1 hover:bg-gray-800 transition"
onClick={() => handleMonthChange(1)}
>
<span className="hidden sm:inline">Next</span>
<ChevronRight size={16} />
</button>
</div>
<div className="grid grid-cols-7 gap-1 mb-2">
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => (
<div key={day} className="text-center font-semibold bg-gray-800 text-white p-1 text-xs sm:text-sm">{day}</div>
))}
</div>
<div className="grid grid-cols-7 gap-1">
{calendarData.map((day, index) => (
<div
key={index}
className={`border rounded p-1 overflow-y-auto ${day ? 'bg-white' : 'bg-gray-100'
}`}
style={{
height: "120px",
maxHeight: "120px"
}}
>
{day && (
<>
<div className={`text-right text-sm font-medium ${new Date().toISOString().split('T')[0] === day.date ?
'bg-red-600 text-white p-1 rounded-full w-6 h-6 flex items-center justify-center ml-auto' :
'text-gray-700'
}`}>
{day.day}
</div>
<div className="overflow-y-auto" style={{ maxHeight: "90px" }}>
{day.results.length > 0 ? (
day.results.map((teamResult, i) => (
<div key={i} className="mt-1 border-t border-gray-200 pt-1">
<div className="font-semibold text-xs text-red-600">{teamResult.team}</div>
{teamResult.results.map((r, j) => (
<div key={j} className="text-xs flex justify-between">
<span className="text-gray-500">{r.time}</span>
<span className="font-bold">{r.result}</span>
</div>
))}
</div>
))
) : (
<div className="text-xs text-gray-400 mt-2 text-center">No results</div>
)}
</div>
</>
)}
</div>
))}
</div>
<div className="mt-4 flex justify-end">
<button
className="bg-black text-white px-4 py-2 rounded hover:bg-gray-800 transition"
onClick={() => setShowCalendar(false)}
>
Back to Results
</button>
</div>
</div>
)}
{/* Teams Table with multiple results support */}
{!loading && !showCalendar && !showChartView && (
<div className="bg-white rounded-b-lg overflow-hidden shadow-lg">
<table className="w-full border-collapse">
<thead>
<tr className="bg-black text-white">
<th className="p-3 text-left">Games List</th>
<th className="p-3 text-center">
{dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 0 && new Date(dates[0]).getDate()}th
</th>
<th className="p-3 text-center">
{dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 1 && new Date(dates[1]).getDate()}th
</th>
<th className="p-3 text-center">Chart</th>
</tr>
</thead>
<tbody>
{teams.map(team => (
<tr key={team.id} className="border-b hover:bg-gray-50">
<td className="p-3">
<div className="font-semibold text-red-600">{team.name}</div>
<div className="text-sm text-gray-500">at {team.time}</div>
<div className="text-xs text-black underline mt-1 cursor-pointer hover:text-red-600" onClick={() => handleViewChart(team)}>Record Chart</div>
</td>
<td className="p-3 text-center">
{dates.length > 0 && team.results[dates[0]] && team.results[dates[0]].length > 0 ? (
<div className="flex flex-col gap-1">
{team.results[dates[0]].map((result, idx) => (
<div key={idx} className="flex flex-col">
<span className="text-2xl font-bold">{result.result}</span>
<span className="text-xs text-gray-500">{result.time}</span>
</div>
))}
</div>
) : (
<span className="text-2xl font-bold text-gray-400">XX</span>
)}
</td>
<td className="p-3 text-center">
{dates.length > 1 && team.results[dates[1]] && team.results[dates[1]].length > 0 ? (
<div className="flex flex-col gap-1">
{team.results[dates[1]].map((result, idx) => (
<div key={idx} className="flex flex-col">
<span className="text-2xl font-bold">{result.result}</span>
<span className="text-xs text-gray-500">{result.time}</span>
</div>
))}
</div>
) : (
<span className="text-2xl font-bold text-gray-400">XX</span>
)}
</td>
<td className="p-3">
<div className="flex justify-center">
<button
className="p-2 bg-red-100 text-red-600 rounded hover:bg-red-200 transition"
onClick={() => handleViewChart(team)}
title="View Monthly Chart"
>
<BarChart2 size={16} />
</button>
</div>
</td>
</tr>
))}
{teams.length === 0 && (
<tr>
<td colSpan="4" className="p-4 text-center">No teams found</td>
</tr>
)}
</tbody>
</table>
<div className="bg-black text-white text-center p-3">
<button className="hover:text-red-400 transition" onClick={handleCalendarView}>Click here for all games results.</button>
</div>
</div>
)}
</div>
<div className="w-full bg-white text-black">
{/* FAQ Section */}
<div className="max-w-6xl mx-auto py-6">
{faqs.map((faq, index) => (
<div key={index} className="mb-2">
<button
className="w-full bg-red-600 text-white text-lg font-semibold py-3 px-4 flex justify-between items-center rounded-md"
onClick={() => toggleFAQ(index)}
>
{faq.question}
<span>{openIndex === index ? "▲" : "▼"}</span>
</button>
{openIndex === index && (
<div className="p-4 bg-gray-100 border border-gray-300">
{faq.answer}
</div>
)}
</div>
))}
</div>
{/* Footer Section */}
<footer className="bg-white border-t py-6 text-center">
<div className="max-w-3xl mx-auto text-gray-600 text-sm">
<p className="font-bold text-xl text-black flex items-center justify-center">
MATKA <span className="text-red-600"> SATTA</span>
</p>
<p className="mt-2">
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.
</p>
<p className="mt-2">
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.
</p>
<p className="mt-4 flex justify-center space-x-4 text-black font-semibold">
<span>Media Center</span>
<span>Legal</span>
<span>Privacy</span>
<span>español</span>
</p>
</div>
</footer>
</div>
</div>
);
};
export default Home2;

282
src/pages/Today.js Normal file
View File

@ -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 (
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
Upcoming
</span>
);
}
// You could add logic here to style different results differently
// For example, showing wins in green, losses in red
return (
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
Completed
</span>
);
};
return (
<div className="bg-white rounded-lg shadow-lg overflow-hidden">
{/* Header */}
<div className="bg-gradient-to-r from-red-600 to-red-800 p-4 text-white">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold">Today's Matches</h1>
<div className="flex items-center space-x-2">
<Calendar className="h-5 w-5" />
<span className="font-medium">{currentDate}</span>
</div>
</div>
</div>
{/* Controls */}
<div className="bg-gray-50 p-4 flex justify-between items-center border-b">
<div className="text-sm font-medium text-gray-500">
{todaysMatches.length > 0 ?
`${todaysMatches.length} teams with matches today` :
"No matches scheduled"}
</div>
<button
className="bg-red-600 text-white px-4 py-2 rounded-md flex items-center gap-2 hover:bg-red-700 transition shadow-sm"
onClick={handleRefresh}
disabled={loading}
>
<RefreshCw size={16} className={loading ? "animate-spin" : ""} />
{loading ? "Refreshing..." : "Refresh"}
</button>
</div>
{/* Loading indicator */}
{loading && (
<div className="p-8 flex justify-center items-center">
<div className="flex items-center gap-2">
<RefreshCw size={24} className="animate-spin text-red-600" />
<span className="text-gray-600 font-medium">Loading match data...</span>
</div>
</div>
)}
{/* Error message */}
{error && (
<div className="bg-red-50 border-l-4 border-red-500 p-4 m-4">
<div className="flex">
<div className="ml-3">
<p className="text-sm text-red-700">{error}</p>
</div>
</div>
</div>
)}
{/* Results display */}
{!loading && !error && (
<div className="p-4">
{todaysMatches.length > 0 ? (
<div className="space-y-4">
{todaysMatches.map((teamData, index) => (
<div key={index} className="border border-gray-200 rounded-lg overflow-hidden shadow-sm">
{/* Team header - clickable to expand/collapse */}
<div
className="bg-gradient-to-r from-gray-800 to-gray-700 text-white p-3 flex justify-between items-center cursor-pointer hover:from-gray-700 hover:to-gray-600 transition"
onClick={() => toggleTeamExpansion(teamData.team)}
>
<div className="font-bold text-lg">{teamData.team}</div>
<div className="flex items-center space-x-4">
<div className="text-xs bg-opacity-20 bg-white px-2 py-1 rounded-full">
<span className="font-medium">{teamData.upcomingCount}</span> upcoming <span className="font-medium">{teamData.completedCount}</span> completed
</div>
{expandedTeams[teamData.team] ? (
<ChevronUp size={20} />
) : (
<ChevronDown size={20} />
)}
</div>
</div>
{/* Team results */}
{expandedTeams[teamData.team] && (
<div className="divide-y divide-gray-100">
{teamData.results.map((result, idx) => (
<div key={idx} className={`p-4 flex justify-between items-center ${result.upcoming ? "bg-blue-50" : "bg-white"}`}>
<div className="flex items-center space-x-3">
<Clock size={16} className="text-gray-400" />
<span className="font-medium">{result.time}</span>
{getStatusBadge(result)}
</div>
<div className="text-xl font-bold">
{result.upcoming ? (
<span className="text-gray-400">--</span>
) : (
<span className="text-gray-800">{result.result}</span>
)}
</div>
</div>
))}
</div>
)}
</div>
))}
</div>
) : (
<div className="text-center p-8">
<div className="mx-auto h-12 w-12 text-gray-400">
<Calendar className="h-12 w-12" />
</div>
<h3 className="mt-2 text-sm font-medium text-gray-900">No matches today</h3>
<p className="mt-1 text-sm text-gray-500">There are no matches scheduled for today.</p>
</div>
)}
</div>
)}
</div>
);
};
export default Today;

298
src/pages/TodaysMatch.js Normal file
View File

@ -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 (
<div className="flex flex-col md:flex-row gap-4">
{/* Today's Matches Box */}
<div className="bg-gray-200 rounded-lg shadow-lg overflow-hidden w-full md:w-1/3">
<div className="bg-white p-4 rounded-t-lg">
<h2 className="text-center font-bold text-xl text-gray-800">Winning Numbers</h2>
</div>
<div className="p-4 text-center">
<h3 className="font-medium text-lg mb-4">{currentDate}</h3>
{loading ? (
<div className="flex justify-center p-6">
<RefreshCw size={24} className="animate-spin text-red-600" />
</div>
) : error ? (
<div className="bg-red-100 border border-red-400 text-red-700 p-3 rounded">
<p>{error}</p>
</div>
) : todaysMatches.length > 0 ? (
<div className="relative">
{/* Navigation buttons */}
<button
onClick={handlePrev}
className="absolute left-0 top-1/2 transform -translate-y-1/2 bg-gray-800 text-white rounded-full p-1 z-10"
>
<ChevronLeft size={20} />
</button>
<button
onClick={handleNext}
className="absolute right-0 top-1/2 transform -translate-y-1/2 bg-gray-800 text-white rounded-full p-1 z-10"
>
<ChevronRight size={20} />
</button>
{/* Current team results */}
<div className="py-2">
<div className="bg-gray-800 text-white p-2 font-semibold rounded-t mb-2">
{todaysMatches[activeTeamIndex]?.team || "No Team"}
</div>
<div className="overflow-y-auto max-h-48">
{todaysMatches[activeTeamIndex]?.results.map((result, idx) => (
<div key={idx} className="flex justify-between items-center bg-white p-3 mb-2 rounded shadow">
<div className="flex items-center gap-2">
<Clock size={16} className="text-gray-500" />
<span>{result.time}</span>
</div>
<div className={`text-xl font-bold ${result.upcoming ? 'text-gray-400' : 'text-red-600'}`}>
{result.upcoming ? "Upcoming" : result.result}
</div>
</div>
))}
</div>
</div>
{/* Team indicators */}
<div className="flex justify-center gap-1 mt-2">
{todaysMatches.map((_, idx) => (
<div
key={idx}
className={`h-2 w-2 rounded-full ${idx === activeTeamIndex ? 'bg-red-600' : 'bg-gray-400'}`}
/>
))}
</div>
</div>
) : (
<div className="text-center p-6 text-gray-500">
No match results available for today.
</div>
)}
<button
className="bg-red-600 text-white px-6 py-2 rounded-full font-bold mt-4 hover:bg-red-700 transition"
onClick={handleRefresh}
>
PLay Now
</button>
{/* <div className="mt-4 grid gap-2">
<button className="bg-gray-800 text-white p-3 rounded font-medium">
VIEW RESULTS
</button>
<button className="bg-gray-800 text-white p-3 rounded font-medium">
CHECK YOUR NUMBERS
</button>
</div> */}
</div>
</div>
{/* Next Drawing Box */}
<div className="bg-gray-200 rounded-lg shadow-lg overflow-hidden w-full md:w-1/3">
<div className="bg-white p-4 rounded-t-lg">
<h2 className="text-center font-bold text-xl text-gray-800">Next Drawing</h2>
</div>
<div className="p-4 text-center">
<h3 className="font-medium text-lg mb-4">Sat, Mar 22, 2025</h3>
<div className="flex justify-center gap-2 my-4">
<div className="bg-gray-800 text-white w-12 h-12 flex items-center justify-center rounded">
<div className="text-xl font-bold">67</div>
</div>
<div className="bg-gray-800 text-white w-12 h-12 flex items-center justify-center rounded">
<div className="text-xl font-bold">58</div>
</div>
<div className="bg-gray-800 text-white w-12 h-12 flex items-center justify-center rounded">
<div className="text-xl font-bold">11</div>
</div>
</div>
<div className="flex justify-center gap-2 text-xs text-gray-600 mb-4">
<div className="text-center w-12">HOURS</div>
<div className="text-center w-12">MINUTES</div>
<div className="text-center w-12">SECONDS</div>
</div>
<div className="bg-gray-800 text-yellow-400 p-2 font-bold mb-2">
ESTIMATED JACKPOT
</div>
<div className="text-red-600 text-4xl font-bold mb-4">
$444 Million
</div>
<div className="bg-gray-800 text-yellow-400 p-2 font-bold mb-2">
CASH VALUE
</div>
<div className="text-red-600 text-4xl font-bold">
$207.2 Million
</div>
</div>
</div>
{/* Winners Box */}
<div className="bg-gray-200 rounded-lg shadow-lg overflow-hidden w-full md:w-1/3">
<div className="bg-white p-4 rounded-t-lg">
<h2 className="text-center font-bold text-xl text-gray-800">Winners</h2>
</div>
<div className="p-4 text-center">
<h3 className="font-medium text-lg mb-4">Wed, Mar 19, 2025</h3>
<div className="text-center mb-4">
<div className="font-bold">POWERBALL</div>
<div className="text-2xl font-bold">JACKPOT WINNERS</div>
<div className="text-red-600 text-xl">None</div>
</div>
<div className="text-center mb-4">
<div className="font-bold">MATCH 5 + POWER PLAY</div>
<div className="text-2xl font-bold">$2 MILLION WINNERS</div>
<div className="text-red-600 text-xl">CO, TX</div>
</div>
<div className="text-center">
<div className="font-bold">MATCH 5</div>
<div className="text-2xl font-bold">$1 MILLION WINNERS</div>
<div className="text-red-600 text-xl">None</div>
</div>
</div>
</div>
</div>
);
};
export default TodaysMatch;