updated
This commit is contained in:
parent
c2edcb5051
commit
330b333a33
0
src/App.css
Normal file
0
src/App.css
Normal file
24
src/App.js
Normal file
24
src/App.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
||||
import Home from "./pages/Home";
|
||||
import Admin from "./pages/Admin";
|
||||
import TeamsResults from "./pages/TeamResult";
|
||||
import AdminPanel from "./pages/AdminPannel";
|
||||
import { SattaUserView } from "./pages/UserView";
|
||||
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/admin" element={<Admin/>}/>
|
||||
<Route path="team" element={<TeamsResults/>}/>
|
||||
|
||||
|
||||
{/* test */}
|
||||
<Route path="/admin2" element={<AdminPanel />} />
|
||||
<Route path="/user2" element={<SattaUserView/>}/>
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
8
src/App.test.js
Normal file
8
src/App.test.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
3
src/index.css
Normal file
3
src/index.css
Normal file
@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
17
src/index.js
Normal file
17
src/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
1
src/logo.svg
Normal file
1
src/logo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
586
src/pages/Admin.js
Normal file
586
src/pages/Admin.js
Normal file
@ -0,0 +1,586 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { PlusCircle, Trash2, Edit, BarChart2, LogIn, Calendar as CalendarIcon } from 'lucide-react';
|
||||
|
||||
const Admin = () => {
|
||||
// Authentication state
|
||||
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
||||
const [authError, setAuthError] = useState('');
|
||||
const [loginData, setLoginData] = useState({ username: '', password: '' });
|
||||
|
||||
// Static credentials - in a real app, these would be stored securely
|
||||
const validCredentials = {
|
||||
username: 'admin',
|
||||
password: 'satta123'
|
||||
};
|
||||
|
||||
const [teams, setTeams] = useState([
|
||||
{ id: 1, name: 'BIKANER SUPER', time: '02:20 AM', results: { '2025-03-11': '04', '2025-03-12': '61' } },
|
||||
{ id: 2, name: 'DESAWAR', time: '05:00 AM', results: { '2025-03-11': '79', '2025-03-12': '55' } },
|
||||
{ id: 3, name: 'FARIDABAD', time: '06:00 PM', results: { '2025-03-11': '78', '2025-03-12': '98' } },
|
||||
{ id: 4, name: 'GHAZIABAD', time: '09:30 PM', results: { '2025-03-11': '19', '2025-03-12': '23' } },
|
||||
{ id: 5, name: 'GALI', time: '11:30 PM', results: { '2025-03-11': '72', '2025-03-12': 'XX' } },
|
||||
]);
|
||||
|
||||
const [selectedTeam, setSelectedTeam] = useState(null);
|
||||
const [showAddForm, setShowAddForm] = useState(false);
|
||||
const [showEditForm, setShowEditForm] = useState(false);
|
||||
const [showChartView, setShowChartView] = useState(false);
|
||||
const [showCalendar, setShowCalendar] = useState(false);
|
||||
const [formData, setFormData] = useState({ name: '', time: '', result: '' });
|
||||
const [dates, setDates] = useState(['2025-03-11', '2025-03-12']);
|
||||
const [currentDate, setCurrentDate] = useState('2025-03-12');
|
||||
|
||||
// Calendar state
|
||||
const [calendarYear, setCalendarYear] = useState(new Date().getFullYear());
|
||||
const [calendarMonth, setCalendarMonth] = useState(new Date().getMonth());
|
||||
|
||||
// Handle login input changes
|
||||
const handleLoginInputChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setLoginData({ ...loginData, [name]: value });
|
||||
setAuthError('');
|
||||
};
|
||||
|
||||
// Handle login submission
|
||||
const handleLogin = (e) => {
|
||||
e.preventDefault();
|
||||
if (loginData.username === validCredentials.username &&
|
||||
loginData.password === validCredentials.password) {
|
||||
setIsAuthenticated(true);
|
||||
setAuthError('');
|
||||
} else {
|
||||
setAuthError('Invalid username or password');
|
||||
}
|
||||
};
|
||||
|
||||
// Handle logout
|
||||
const handleLogout = () => {
|
||||
setIsAuthenticated(false);
|
||||
setLoginData({ username: '', password: '' });
|
||||
};
|
||||
|
||||
// Handle input changes for team forms
|
||||
const handleInputChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData({ ...formData, [name]: value });
|
||||
};
|
||||
|
||||
// Add new team
|
||||
const handleAddTeam = () => {
|
||||
const newTeam = {
|
||||
id: teams.length + 1,
|
||||
name: formData.name,
|
||||
time: formData.time,
|
||||
results: {
|
||||
[dates[0]]: '',
|
||||
[dates[1]]: ''
|
||||
}
|
||||
};
|
||||
setTeams([...teams, newTeam]);
|
||||
setFormData({ name: '', time: '', result: '' });
|
||||
setShowAddForm(false);
|
||||
};
|
||||
|
||||
// Delete team
|
||||
const handleDeleteTeam = (id) => {
|
||||
setTeams(teams.filter(team => team.id !== id));
|
||||
};
|
||||
|
||||
// Select team for editing
|
||||
const handleSelectTeam = (team) => {
|
||||
setSelectedTeam(team);
|
||||
setFormData({
|
||||
name: team.name,
|
||||
time: team.time,
|
||||
result: team.results[currentDate] || ''
|
||||
});
|
||||
setShowEditForm(true);
|
||||
setShowChartView(false);
|
||||
};
|
||||
|
||||
// Update team
|
||||
const handleUpdateTeam = () => {
|
||||
const updatedTeams = teams.map(team => {
|
||||
if (team.id === selectedTeam.id) {
|
||||
const updatedResults = { ...team.results };
|
||||
updatedResults[currentDate] = formData.result;
|
||||
|
||||
return {
|
||||
...team,
|
||||
name: formData.name,
|
||||
time: formData.time,
|
||||
results: updatedResults
|
||||
};
|
||||
}
|
||||
return team;
|
||||
});
|
||||
|
||||
setTeams(updatedTeams);
|
||||
setShowEditForm(false);
|
||||
setSelectedTeam(null);
|
||||
setFormData({ name: '', time: '', result: '' });
|
||||
};
|
||||
|
||||
// Show chart for selected team
|
||||
const handleViewChart = (team) => {
|
||||
setSelectedTeam(team);
|
||||
setShowChartView(true);
|
||||
setShowEditForm(false);
|
||||
};
|
||||
|
||||
// Generate mock chart data for the selected team
|
||||
const generateChartData = () => {
|
||||
if (!selectedTeam) return [];
|
||||
|
||||
// Generate some random data for demonstration
|
||||
const mockData = [];
|
||||
const currentDate = new Date();
|
||||
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const date = new Date(currentDate);
|
||||
date.setDate(date.getDate() - i);
|
||||
const dateStr = date.toISOString().split('T')[0];
|
||||
|
||||
mockData.unshift({
|
||||
date: dateStr,
|
||||
result: Math.floor(Math.random() * 100).toString().padStart(2, '0')
|
||||
});
|
||||
}
|
||||
|
||||
return mockData;
|
||||
};
|
||||
|
||||
// Calendar helpers
|
||||
const getDaysInMonth = (year, month) => {
|
||||
return new Date(year, month + 1, 0).getDate();
|
||||
};
|
||||
|
||||
const getFirstDayOfMonth = (year, month) => {
|
||||
return new Date(year, month, 1).getDay();
|
||||
};
|
||||
|
||||
const handlePrevMonth = () => {
|
||||
if (calendarMonth === 0) {
|
||||
setCalendarMonth(11);
|
||||
setCalendarYear(calendarYear - 1);
|
||||
} else {
|
||||
setCalendarMonth(calendarMonth - 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleNextMonth = () => {
|
||||
if (calendarMonth === 11) {
|
||||
setCalendarMonth(0);
|
||||
setCalendarYear(calendarYear + 1);
|
||||
} else {
|
||||
setCalendarMonth(calendarMonth + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDateSelect = (day) => {
|
||||
const selectedDate = new Date(calendarYear, calendarMonth, day);
|
||||
const formattedDate = selectedDate.toISOString().split('T')[0];
|
||||
|
||||
// Check if the date is in the dates array
|
||||
if (!dates.includes(formattedDate)) {
|
||||
// Add the date to the dates array
|
||||
const newDates = [...dates, formattedDate].sort();
|
||||
setDates(newDates);
|
||||
|
||||
// Update teams with the new date
|
||||
const updatedTeams = teams.map(team => {
|
||||
const updatedResults = { ...team.results };
|
||||
if (!updatedResults[formattedDate]) {
|
||||
updatedResults[formattedDate] = '';
|
||||
}
|
||||
return { ...team, results: updatedResults };
|
||||
});
|
||||
|
||||
setTeams(updatedTeams);
|
||||
}
|
||||
|
||||
setCurrentDate(formattedDate);
|
||||
setShowCalendar(false);
|
||||
};
|
||||
|
||||
// Calendar component
|
||||
const CalendarComponent = () => {
|
||||
const monthNames = ["January", "February", "March", "April", "May", "June",
|
||||
"July", "August", "September", "October", "November", "December"
|
||||
];
|
||||
|
||||
const daysInMonth = getDaysInMonth(calendarYear, calendarMonth);
|
||||
const firstDay = getFirstDayOfMonth(calendarYear, calendarMonth);
|
||||
|
||||
const renderCalendarDays = () => {
|
||||
const days = [];
|
||||
|
||||
// Add empty cells for days before the first day of the month
|
||||
for (let i = 0; i < firstDay; i++) {
|
||||
days.push(<div key={`empty-${i}`} className="h-8 w-8"></div>);
|
||||
}
|
||||
|
||||
// Add cells for each day of the month
|
||||
for (let day = 1; day <= daysInMonth; day++) {
|
||||
const date = new Date(calendarYear, calendarMonth, day).toISOString().split('T')[0];
|
||||
const isSelected = dates.includes(date);
|
||||
const isCurrentDate = date === currentDate;
|
||||
|
||||
days.push(
|
||||
<div
|
||||
key={day}
|
||||
className={`h-8 w-8 flex items-center justify-center rounded-full cursor-pointer ${
|
||||
isSelected ? 'bg-blue-100' : ''
|
||||
} ${
|
||||
isCurrentDate ? 'bg-blue-500 text-white' : ''
|
||||
} hover:bg-blue-200`}
|
||||
onClick={() => handleDateSelect(day)}
|
||||
>
|
||||
{day}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return days;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded shadow p-4 absolute top-full mt-1 right-0 z-10 w-[230px]">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<button onClick={handlePrevMonth} className="p-1 rounded hover:bg-gray-100">
|
||||
<
|
||||
</button>
|
||||
<div className="font-semibold">
|
||||
{monthNames[calendarMonth]} {calendarYear}
|
||||
</div>
|
||||
<button onClick={handleNextMonth} className="p-1 rounded hover:bg-gray-100">
|
||||
>
|
||||
</button>
|
||||
</div>
|
||||
<div className="grid grid-cols-7 gap-1 mb-2">
|
||||
{['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'].map(day => (
|
||||
<div key={day} className="text-center text-xs font-medium text-gray-500">
|
||||
{day}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="grid grid-cols-7 gap-1">
|
||||
{renderCalendarDays()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Login Screen Component
|
||||
const LoginScreen = () => {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen bg-gray-100">
|
||||
<div className="w-full max-w-md">
|
||||
<div className="bg-emerald-400 p-4 text-white text-center text-xl font-bold rounded-t-lg">
|
||||
Bikaner Super Satta Admin Login
|
||||
</div>
|
||||
<form
|
||||
className="bg-white shadow-md rounded-b-lg px-8 pt-6 pb-8 mb-4"
|
||||
onSubmit={handleLogin}
|
||||
>
|
||||
{authError && (
|
||||
<div className="mb-4 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded">
|
||||
{authError}
|
||||
</div>
|
||||
)}
|
||||
<div className="mb-4">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="username">
|
||||
Username
|
||||
</label>
|
||||
<input
|
||||
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
||||
id="username"
|
||||
type="text"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
value={loginData.username}
|
||||
onChange={handleLoginInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-6">
|
||||
<label className="block text-gray-700 text-sm font-bold mb-2" htmlFor="password">
|
||||
Password
|
||||
</label>
|
||||
<input
|
||||
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline"
|
||||
id="password"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="******************"
|
||||
value={loginData.password}
|
||||
onChange={handleLoginInputChange}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center justify-center">
|
||||
<button
|
||||
className="bg-emerald-500 hover:bg-emerald-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline flex items-center gap-2"
|
||||
type="submit"
|
||||
>
|
||||
<LogIn size={16} />
|
||||
Sign In
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Render login screen if not authenticated
|
||||
if (!isAuthenticated) {
|
||||
return <LoginScreen />;
|
||||
}
|
||||
|
||||
// Render admin panel if authenticated
|
||||
return (
|
||||
<div className="bg-gray-100 min-h-screen p-4">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="bg-emerald-400 p-4 text-white flex justify-between items-center rounded-t-lg">
|
||||
<span className="text-xl font-bold">Bikaner Super Satta Result Admin Panel</span>
|
||||
<button
|
||||
className="bg-white text-emerald-700 px-3 py-1 rounded text-sm"
|
||||
onClick={handleLogout}
|
||||
>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Controls */}
|
||||
<div className="bg-white p-4 mb-4 flex justify-between items-center">
|
||||
<button
|
||||
className="bg-green-500 text-white px-4 py-2 rounded flex items-center gap-2"
|
||||
onClick={() => {
|
||||
setShowAddForm(true);
|
||||
setShowEditForm(false);
|
||||
setShowChartView(false);
|
||||
setFormData({ name: '', time: '', result: '' });
|
||||
}}
|
||||
>
|
||||
<PlusCircle size={16} />
|
||||
Add Team
|
||||
</button>
|
||||
|
||||
<div className="relative">
|
||||
<div className="flex items-center gap-2">
|
||||
<select
|
||||
className="border p-2 rounded"
|
||||
value={currentDate}
|
||||
onChange={(e) => setCurrentDate(e.target.value)}
|
||||
>
|
||||
{dates.map(date => (
|
||||
<option key={date} value={date}>
|
||||
{new Date(date).toLocaleDateString()}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
className="bg-blue-500 text-white p-2 rounded flex items-center"
|
||||
onClick={() => setShowCalendar(!showCalendar)}
|
||||
>
|
||||
<CalendarIcon size={16} />
|
||||
</button>
|
||||
</div>
|
||||
{showCalendar && <CalendarComponent />}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Add Form */}
|
||||
{showAddForm && (
|
||||
<div className="bg-white p-4 mb-4 rounded shadow">
|
||||
<h2 className="text-lg font-semibold mb-4">Add New Team</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Team Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Time</label>
|
||||
<input
|
||||
type="text"
|
||||
name="time"
|
||||
value={formData.time}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
placeholder="e.g. 02:20 AM"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex justify-end gap-2">
|
||||
<button
|
||||
className="bg-gray-300 px-4 py-2 rounded"
|
||||
onClick={() => setShowAddForm(false)}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="bg-green-500 text-white px-4 py-2 rounded"
|
||||
onClick={handleAddTeam}
|
||||
>
|
||||
Add Team
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Edit Form */}
|
||||
{showEditForm && selectedTeam && (
|
||||
<div className="bg-white p-4 mb-4 rounded shadow">
|
||||
<h2 className="text-lg font-semibold mb-4">Edit Team: {selectedTeam.name}</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Team Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Time</label>
|
||||
<input
|
||||
type="text"
|
||||
name="time"
|
||||
value={formData.time}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Result for {new Date(currentDate).toLocaleDateString()}</label>
|
||||
<input
|
||||
type="text"
|
||||
name="result"
|
||||
value={formData.result}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
placeholder="e.g. 61"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex justify-end gap-2">
|
||||
<button
|
||||
className="bg-gray-300 px-4 py-2 rounded"
|
||||
onClick={() => setShowEditForm(false)}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="bg-blue-500 text-white px-4 py-2 rounded"
|
||||
onClick={handleUpdateTeam}
|
||||
>
|
||||
Update Team
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Chart View */}
|
||||
{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>
|
||||
{generateChartData().map((item, index) => (
|
||||
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
|
||||
<td className="border p-2">{new Date(item.date).toLocaleDateString()}</td>
|
||||
<td className="border p-2 text-right font-bold">{item.result}</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 List
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Teams Table */}
|
||||
<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">
|
||||
{new Date(dates[0]).toLocaleDateString()} <br/>
|
||||
{new Date(dates[0]).toLocaleDateString("en-US", {weekday: 'short'})}
|
||||
</th>
|
||||
<th className="p-3 text-center">
|
||||
{new Date(dates[1]).toLocaleDateString()} <br/>
|
||||
{new Date(dates[1]).toLocaleDateString("en-US", {weekday: 'short'})}
|
||||
</th>
|
||||
<th className="p-3 text-center">Actions</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>
|
||||
</td>
|
||||
<td className="p-3 text-center text-2xl font-bold">{team.results[dates[0]] || 'XX'}</td>
|
||||
<td className="p-3 text-center text-2xl font-bold">{team.results[dates[1]] || 'XX'}</td>
|
||||
<td className="p-3">
|
||||
<div className="flex justify-center gap-2">
|
||||
<button
|
||||
className="p-2 bg-blue-100 text-blue-600 rounded"
|
||||
onClick={() => handleSelectTeam(team)}
|
||||
title="Edit Team"
|
||||
>
|
||||
<Edit size={16} />
|
||||
</button>
|
||||
<button
|
||||
className="p-2 bg-red-100 text-red-600 rounded"
|
||||
onClick={() => handleDeleteTeam(team.id)}
|
||||
title="Delete Team"
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</button>
|
||||
<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>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Admin;
|
||||
386
src/pages/AdminPannel.js
Normal file
386
src/pages/AdminPannel.js
Normal file
@ -0,0 +1,386 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { PlusCircle, Trash2, Edit, BarChart2 } from 'lucide-react';
|
||||
// import dataService from '../services/dataService';
|
||||
import dataService from '../services/DataService';
|
||||
|
||||
const AdminPanel = () => {
|
||||
const [teams, setTeams] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
const [selectedTeam, setSelectedTeam] = useState(null);
|
||||
const [showAddForm, setShowAddForm] = useState(false);
|
||||
const [showEditForm, setShowEditForm] = useState(false);
|
||||
const [showChartView, setShowChartView] = useState(false);
|
||||
const [formData, setFormData] = useState({ name: '', time: '', result: '' });
|
||||
const [dates] = useState(['2025-03-11', '2025-03-12']);
|
||||
const [currentDate, setCurrentDate] = useState('2025-03-12');
|
||||
|
||||
// Fetch teams on component mount
|
||||
useEffect(() => {
|
||||
const fetchTeams = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await dataService.getTeams();
|
||||
setTeams(data);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
setError('Failed to load teams data');
|
||||
console.error(err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchTeams();
|
||||
|
||||
// Subscribe to real-time updates
|
||||
const unsubscribe = dataService.subscribeToUpdates((updatedTeams) => {
|
||||
setTeams(updatedTeams);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Handle input changes
|
||||
const handleInputChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData({ ...formData, [name]: value });
|
||||
};
|
||||
|
||||
// Add new team
|
||||
const handleAddTeam = async () => {
|
||||
try {
|
||||
const newTeamData = {
|
||||
name: formData.name,
|
||||
time: formData.time,
|
||||
results: {
|
||||
[dates[0]]: '',
|
||||
[dates[1]]: ''
|
||||
}
|
||||
};
|
||||
|
||||
await dataService.addTeam(newTeamData);
|
||||
setFormData({ name: '', time: '', result: '' });
|
||||
setShowAddForm(false);
|
||||
} catch (err) {
|
||||
setError('Failed to add team');
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Delete team
|
||||
const handleDeleteTeam = async (id) => {
|
||||
try {
|
||||
await dataService.deleteTeam(id);
|
||||
} catch (err) {
|
||||
setError('Failed to delete team');
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Select team for editing
|
||||
const handleSelectTeam = (team) => {
|
||||
setSelectedTeam(team);
|
||||
setFormData({
|
||||
name: team.name,
|
||||
time: team.time,
|
||||
result: team.results[currentDate] || ''
|
||||
});
|
||||
setShowEditForm(true);
|
||||
setShowChartView(false);
|
||||
};
|
||||
|
||||
// Update team
|
||||
const handleUpdateTeam = async () => {
|
||||
try {
|
||||
if (!selectedTeam) return;
|
||||
|
||||
const updatedResults = { ...selectedTeam.results };
|
||||
updatedResults[currentDate] = formData.result;
|
||||
|
||||
const updatedTeamData = {
|
||||
name: formData.name,
|
||||
time: formData.time,
|
||||
results: updatedResults
|
||||
};
|
||||
|
||||
await dataService.updateTeam(selectedTeam.id, updatedTeamData);
|
||||
setShowEditForm(false);
|
||||
setSelectedTeam(null);
|
||||
setFormData({ name: '', time: '', result: '' });
|
||||
} catch (err) {
|
||||
setError('Failed to update team');
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Show chart for selected team
|
||||
const handleViewChart = (team) => {
|
||||
setSelectedTeam(team);
|
||||
setShowChartView(true);
|
||||
setShowEditForm(false);
|
||||
};
|
||||
|
||||
// Generate mock chart data for the selected team
|
||||
const generateChartData = () => {
|
||||
if (!selectedTeam) return [];
|
||||
|
||||
// Generate some random data for demonstration
|
||||
const mockData = [];
|
||||
const currentDate = new Date();
|
||||
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const date = new Date(currentDate);
|
||||
date.setDate(date.getDate() - i);
|
||||
const dateStr = date.toISOString().split('T')[0];
|
||||
|
||||
mockData.unshift({
|
||||
date: dateStr,
|
||||
result: Math.floor(Math.random() * 100).toString().padStart(2, '0')
|
||||
});
|
||||
}
|
||||
|
||||
return mockData;
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="flex justify-center items-center h-screen">Loading...</div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div className="flex justify-center items-center h-screen text-red-500">{error}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-gray-100 min-h-screen p-4">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="bg-emerald-400 p-4 text-white text-center text-xl font-bold rounded-t-lg">
|
||||
Bikaner Super Satta Result Admin Panel
|
||||
</div>
|
||||
|
||||
{/* Controls */}
|
||||
<div className="bg-white p-4 mb-4 flex justify-between items-center">
|
||||
<button
|
||||
className="bg-green-500 text-white px-4 py-2 rounded flex items-center gap-2"
|
||||
onClick={() => {
|
||||
setShowAddForm(true);
|
||||
setShowEditForm(false);
|
||||
setShowChartView(false);
|
||||
setFormData({ name: '', time: '', result: '' });
|
||||
}}
|
||||
>
|
||||
<PlusCircle size={16} />
|
||||
Add Team
|
||||
</button>
|
||||
|
||||
<div>
|
||||
<select
|
||||
className="border p-2 rounded"
|
||||
value={currentDate}
|
||||
onChange={(e) => setCurrentDate(e.target.value)}
|
||||
>
|
||||
{dates.map(date => (
|
||||
<option key={date} value={date}>
|
||||
{new Date(date).toLocaleDateString()}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Add Form */}
|
||||
{showAddForm && (
|
||||
<div className="bg-white p-4 mb-4 rounded shadow">
|
||||
<h2 className="text-lg font-semibold mb-4">Add New Team</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Team Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Time</label>
|
||||
<input
|
||||
type="text"
|
||||
name="time"
|
||||
value={formData.time}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
placeholder="e.g. 02:20 AM"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex justify-end gap-2">
|
||||
<button
|
||||
className="bg-gray-300 px-4 py-2 rounded"
|
||||
onClick={() => setShowAddForm(false)}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="bg-green-500 text-white px-4 py-2 rounded"
|
||||
onClick={handleAddTeam}
|
||||
>
|
||||
Add Team
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Edit Form */}
|
||||
{showEditForm && selectedTeam && (
|
||||
<div className="bg-white p-4 mb-4 rounded shadow">
|
||||
<h2 className="text-lg font-semibold mb-4">Edit Team: {selectedTeam.name}</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Team Name</label>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
value={formData.name}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Time</label>
|
||||
<input
|
||||
type="text"
|
||||
name="time"
|
||||
value={formData.time}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-1">Result for {new Date(currentDate).toLocaleDateString()}</label>
|
||||
<input
|
||||
type="text"
|
||||
name="result"
|
||||
value={formData.result}
|
||||
onChange={handleInputChange}
|
||||
className="w-full p-2 border rounded"
|
||||
placeholder="e.g. 61"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-4 flex justify-end gap-2">
|
||||
<button
|
||||
className="bg-gray-300 px-4 py-2 rounded"
|
||||
onClick={() => setShowEditForm(false)}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="bg-blue-500 text-white px-4 py-2 rounded"
|
||||
onClick={handleUpdateTeam}
|
||||
>
|
||||
Update Team
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Chart View */}
|
||||
{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>
|
||||
{generateChartData().map((item, index) => (
|
||||
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
|
||||
<td className="border p-2">{new Date(item.date).toLocaleDateString()}</td>
|
||||
<td className="border p-2 text-right font-bold">{item.result}</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 List
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Teams Table */}
|
||||
<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">
|
||||
{new Date(dates[0]).toLocaleDateString()} <br/>
|
||||
{new Date(dates[0]).toLocaleDateString("en-US", {weekday: 'short'})}
|
||||
</th>
|
||||
<th className="p-3 text-center">
|
||||
{new Date(dates[1]).toLocaleDateString()} <br/>
|
||||
{new Date(dates[1]).toLocaleDateString("en-US", {weekday: 'short'})}
|
||||
</th>
|
||||
<th className="p-3 text-center">Actions</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>
|
||||
</td>
|
||||
<td className="p-3 text-center text-2xl font-bold">{team.results[dates[0]] || 'XX'}</td>
|
||||
<td className="p-3 text-center text-2xl font-bold">{team.results[dates[1]] || 'XX'}</td>
|
||||
<td className="p-3">
|
||||
<div className="flex justify-center gap-2">
|
||||
<button
|
||||
className="p-2 bg-blue-100 text-blue-600 rounded"
|
||||
onClick={() => handleSelectTeam(team)}
|
||||
title="Edit Team"
|
||||
>
|
||||
<Edit size={16} />
|
||||
</button>
|
||||
<button
|
||||
className="p-2 bg-red-100 text-red-600 rounded"
|
||||
onClick={() => handleDeleteTeam(team.id)}
|
||||
title="Delete Team"
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</button>
|
||||
<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>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AdminPanel;
|
||||
281
src/pages/Home.js
Normal file
281
src/pages/Home.js
Normal file
@ -0,0 +1,281 @@
|
||||
import React, { useState } from 'react';
|
||||
import { BarChart2, Calendar } from 'lucide-react';
|
||||
import { useEffect } from 'react';
|
||||
const Home = () => {
|
||||
const [teams, setTeams] = useState([
|
||||
{ id: 1, name: 'BIKANER SUPER', time: '02:20 AM', results: { '2025-03-11': '04', '2025-03-12': '61' } },
|
||||
{ id: 2, name: 'DESAWAR', time: '05:00 AM', results: { '2025-03-11': '79', '2025-03-12': '55' } },
|
||||
{ id: 3, name: 'FARIDABAD', time: '06:00 PM', results: { '2025-03-11': '78', '2025-03-12': '98' } },
|
||||
{ id: 4, name: 'GHAZIABAD', time: '09:30 PM', results: { '2025-03-11': '19', '2025-03-12': '23' } },
|
||||
{ id: 5, name: 'GALI', time: '11:30 PM', results: { '2025-03-11': '72', '2025-03-12': 'XX' } },
|
||||
]);
|
||||
|
||||
const [dates] = useState(['2025-03-11', '2025-03-12']);
|
||||
const [selectedTeam, setSelectedTeam] = useState(null);
|
||||
const [showChartView, setShowChartView] = useState(false);
|
||||
const [showCalendar, setShowCalendar] = useState(false);
|
||||
|
||||
|
||||
|
||||
// Show chart for selected team
|
||||
const handleViewChart = (team) => {
|
||||
setSelectedTeam(team);
|
||||
setShowChartView(true);
|
||||
setShowCalendar(false);
|
||||
};
|
||||
|
||||
// Generate mock chart data for the selected team
|
||||
const generateChartData = () => {
|
||||
if (!selectedTeam) return [];
|
||||
|
||||
// Generate some random data for demonstration
|
||||
const mockData = [];
|
||||
const currentDate = new Date();
|
||||
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const date = new Date(currentDate);
|
||||
date.setDate(date.getDate() - i);
|
||||
const dateStr = date.toISOString().split('T')[0];
|
||||
|
||||
mockData.unshift({
|
||||
date: dateStr,
|
||||
result: Math.floor(Math.random() * 100).toString().padStart(2, '0')
|
||||
});
|
||||
}
|
||||
|
||||
return mockData;
|
||||
};
|
||||
|
||||
// Generate calendar view with results
|
||||
const generateCalendarData = () => {
|
||||
const calendarDays = [];
|
||||
const currentDate = new Date();
|
||||
const firstDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
|
||||
const lastDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
|
||||
|
||||
// Add empty cells for days before the first of the month
|
||||
const firstDayWeekday = firstDayOfMonth.getDay();
|
||||
for (let i = 0; i < firstDayWeekday; i++) {
|
||||
calendarDays.push(null);
|
||||
}
|
||||
|
||||
// Add days of the month
|
||||
for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
|
||||
const date = new Date(currentDate.getFullYear(), currentDate.getMonth(), i);
|
||||
const dateStr = date.toISOString().split('T')[0];
|
||||
|
||||
// Generate mock results for each team on this date
|
||||
const dayResults = {};
|
||||
teams.forEach(team => {
|
||||
dayResults[team.id] = Math.floor(Math.random() * 100).toString().padStart(2, '0');
|
||||
});
|
||||
|
||||
calendarDays.push({
|
||||
day: i,
|
||||
date: dateStr,
|
||||
results: dayResults
|
||||
});
|
||||
}
|
||||
|
||||
return calendarDays;
|
||||
};
|
||||
|
||||
const [currentTime, setCurrentTime] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
const now = new Date();
|
||||
const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" });
|
||||
setCurrentTime(formattedTime);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-gray-100 min-h-screen p-4">
|
||||
<div className="w-full bg-gray-100 p-4 text-center">
|
||||
{/* Header */}
|
||||
<h1 className="text-3xl font-bold text-black uppercase">SATTA-KING-FAST.com</h1>
|
||||
|
||||
{/* Advertisement Banner */}
|
||||
<div className="mt-4 flex justify-center items-center">
|
||||
<img
|
||||
src="/path-to-your-advertisement-image.jpg"
|
||||
alt="Advertisement"
|
||||
className="w-full max-w-4xl"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Informational Text */}
|
||||
<p className="mt-4 text-gray-700 text-sm p-1 w-[100%] 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.
|
||||
</p>
|
||||
|
||||
{/* Disclaimer */}
|
||||
<p className="mt-2 text-blue-600 text-sm font-medium bg-white p-1 w-[100%] 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.
|
||||
</p>
|
||||
|
||||
{/* Warning Message */}
|
||||
<p className="mt-2 text-red-600 font-bold bg-white p-1 w-[100%] lg:w-3/4 m-auto">
|
||||
कृपया ध्यान दें, लीक गेम के नाम पर किसी को कोई पैसा न दें, ना पहले ना बाद में - धन्यवाद
|
||||
</p>
|
||||
|
||||
{/* Contact Link */}
|
||||
<p className="mt-2 text-green-600 font-medium bg-white p-1 w-[100%] lg:w-3/4 m-auto">
|
||||
हमसे संपर्क करने के लिए ➡ <a href="#" className="underline">यहाँ क्लिक करें</a>
|
||||
</p>
|
||||
|
||||
{/* Timestamp */}
|
||||
<p className="mt-2 text-gray-600 text-xs">
|
||||
Updated: {currentTime} IST.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="bg-emerald-400 p-4 text-white text-center text-xl font-bold rounded-t-lg">
|
||||
Bikaner Super Satta Result of March 12, 2025 & March 11, 2025
|
||||
</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">
|
||||
<button
|
||||
className="bg-blue-500 text-white px-4 py-2 rounded flex items-center gap-2"
|
||||
onClick={() => {
|
||||
setShowCalendar(true);
|
||||
setShowChartView(false);
|
||||
}}
|
||||
>
|
||||
<Calendar size={16} />
|
||||
Calendar View
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Chart View */}
|
||||
{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>
|
||||
{generateChartData().map((item, index) => (
|
||||
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
|
||||
<td className="border p-2">{new Date(item.date).toLocaleDateString()}</td>
|
||||
<td className="border p-2 text-right font-bold">{item.result}</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 */}
|
||||
{showCalendar && (
|
||||
<div className="bg-white p-4 mb-4 rounded shadow">
|
||||
<h2 className="text-lg font-semibold mb-4">
|
||||
Calendar View: {new Date().toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
|
||||
</h2>
|
||||
|
||||
<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">
|
||||
{generateCalendarData().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">
|
||||
<span className="font-semibold">{team.name.split(' ')[0]}:</span> {day.results[team.id]}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex justify-end">
|
||||
<button
|
||||
className="bg-gray-300 px-4 py-2 rounded"
|
||||
onClick={() => setShowCalendar(false)}
|
||||
>
|
||||
Back to Results
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Teams Table */}
|
||||
{!showCalendar && (
|
||||
<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">
|
||||
{new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {new Date(dates[0]).getDate()}th
|
||||
</th>
|
||||
<th className="p-3 text-center">
|
||||
{new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {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">Record Chart</div>
|
||||
</td>
|
||||
<td className="p-3 text-center text-2xl font-bold">{team.results[dates[0]] || 'XX'}</td>
|
||||
<td className="p-3 text-center text-2xl font-bold">{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>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div className="bg-gray-700 text-white text-center p-3">
|
||||
<button className="hover:underline">Click here for all games results.</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
58
src/pages/TeamResult.js
Normal file
58
src/pages/TeamResult.js
Normal file
@ -0,0 +1,58 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
const TeamResults = () => {
|
||||
const [teams, setTeams] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response = await fetch("http://localhost:5000/api/teams/");
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json(); // Parse JSON response
|
||||
setTeams(data); // Store the entire API response in state
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
setError(error.message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
if (loading) return <p>Loading...</p>;
|
||||
if (error) return <p>Error: {error}</p>;
|
||||
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h2 className="text-xl font-bold mb-4">Game Results</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{teams.map((team) => (
|
||||
<div key={team.id} className="border p-4 rounded-md shadow-md">
|
||||
<h3 className="text-lg font-semibold">{team.name}</h3>
|
||||
<p className="text-sm text-gray-600">Time: {team.time}</p>
|
||||
<div className="mt-2">
|
||||
<h4 className="font-semibold">Results:</h4>
|
||||
<ul className="list-disc pl-4">
|
||||
{Object.entries(team.results).map(([date, result]) => (
|
||||
<li key={date}>
|
||||
<span className="font-medium">{date}:</span> {result}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TeamResults;
|
||||
264
src/pages/UserView.js
Normal file
264
src/pages/UserView.js
Normal file
@ -0,0 +1,264 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { BarChart2, Calendar } from 'lucide-react';
|
||||
import DataService from '../services/DataService';
|
||||
|
||||
export const SattaUserView = () => {
|
||||
const [teams, setTeams] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
const [dates] = useState(['2025-03-11', '2025-03-12']);
|
||||
const [selectedTeam, setSelectedTeam] = useState(null);
|
||||
const [showChartView, setShowChartView] = useState(false);
|
||||
const [showCalendar, setShowCalendar] = useState(false);
|
||||
|
||||
// Fetch teams on component mount
|
||||
useEffect(() => {
|
||||
const fetchTeams = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await DataService.getTeams();
|
||||
setTeams(data);
|
||||
setError(null);
|
||||
} catch (err) {
|
||||
setError('Failed to load teams data');
|
||||
console.error(err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchTeams();
|
||||
|
||||
// Subscribe to real-time updates
|
||||
const unsubscribe = DataService.subscribeToUpdates((updatedTeams) => {
|
||||
setTeams(updatedTeams);
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Show chart for selected team
|
||||
const handleViewChart = (team) => {
|
||||
setSelectedTeam(team);
|
||||
setShowChartView(true);
|
||||
setShowCalendar(false);
|
||||
};
|
||||
|
||||
// Generate mock chart data for the selected team
|
||||
const generateChartData = () => {
|
||||
if (!selectedTeam) return [];
|
||||
|
||||
// Generate some random data for demonstration
|
||||
const mockData = [];
|
||||
const currentDate = new Date();
|
||||
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const date = new Date(currentDate);
|
||||
date.setDate(date.getDate() - i);
|
||||
const dateStr = date.toISOString().split('T')[0];
|
||||
|
||||
mockData.unshift({
|
||||
date: dateStr,
|
||||
result: Math.floor(Math.random() * 100).toString().padStart(2, '0')
|
||||
});
|
||||
}
|
||||
|
||||
return mockData;
|
||||
};
|
||||
|
||||
// Generate calendar view with results
|
||||
const generateCalendarData = () => {
|
||||
const calendarDays = [];
|
||||
const currentDate = new Date();
|
||||
const firstDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
|
||||
const lastDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
|
||||
|
||||
// Add empty cells for days before the first of the month
|
||||
const firstDayWeekday = firstDayOfMonth.getDay();
|
||||
for (let i = 0; i < firstDayWeekday; i++) {
|
||||
calendarDays.push(null);
|
||||
}
|
||||
|
||||
// Add days of the month
|
||||
for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
|
||||
const date = new Date(currentDate.getFullYear(), currentDate.getMonth(), i);
|
||||
const dateStr = date.toISOString().split('T')[0];
|
||||
|
||||
// Generate mock results for each team on this date
|
||||
const dayResults = {};
|
||||
teams.forEach(team => {
|
||||
dayResults[team.id] = Math.floor(Math.random() * 100).toString().padStart(2, '0');
|
||||
});
|
||||
|
||||
calendarDays.push({
|
||||
day: i,
|
||||
date: dateStr,
|
||||
results: dayResults
|
||||
});
|
||||
}
|
||||
|
||||
return calendarDays;
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <div className="flex justify-center items-center h-screen">Loading...</div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div className="flex justify-center items-center h-screen text-red-500">{error}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-gray-100 min-h-screen p-4">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
<div className="bg-emerald-400 p-4 text-white text-center text-xl font-bold rounded-t-lg">
|
||||
Bikaner Super Satta Result of March 12, 2025 & March 11, 2025
|
||||
</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">
|
||||
<button
|
||||
className="bg-blue-500 text-white px-4 py-2 rounded flex items-center gap-2"
|
||||
onClick={() => {
|
||||
setShowCalendar(true);
|
||||
setShowChartView(false);
|
||||
}}
|
||||
>
|
||||
<Calendar size={16} />
|
||||
Calendar View
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Chart View */}
|
||||
{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>
|
||||
{generateChartData().map((item, index) => (
|
||||
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
|
||||
<td className="border p-2">{new Date(item.date).toLocaleDateString()}</td>
|
||||
<td className="border p-2 text-right font-bold">{item.result}</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 */}
|
||||
{showCalendar && (
|
||||
<div className="bg-white p-4 mb-4 rounded shadow">
|
||||
<h2 className="text-lg font-semibold mb-4">
|
||||
Calendar View: {new Date().toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
|
||||
</h2>
|
||||
|
||||
<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">
|
||||
{generateCalendarData().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">
|
||||
<span className="font-semibold">{team.name.split(' ')[0]}:</span> {day.results[team.id]}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex justify-end">
|
||||
<button
|
||||
className="bg-gray-300 px-4 py-2 rounded"
|
||||
onClick={() => setShowCalendar(false)}
|
||||
>
|
||||
Back to Results
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Teams Table */}
|
||||
{!showCalendar && (
|
||||
<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">
|
||||
{new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {new Date(dates[0]).getDate()}th
|
||||
</th>
|
||||
<th className="p-3 text-center">
|
||||
{new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {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">Record Chart</div>
|
||||
</td>
|
||||
<td className="p-3 text-center text-2xl font-bold">{team.results[dates[0]] || 'XX'}</td>
|
||||
<td className="p-3 text-center text-2xl font-bold">{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>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div className="bg-gray-700 text-white text-center p-3">
|
||||
<button className="hover:underline">Click here for all games results.</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
};
|
||||
13
src/reportWebVitals.js
Normal file
13
src/reportWebVitals.js
Normal file
@ -0,0 +1,13 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
65
src/services/DataService.js
Normal file
65
src/services/DataService.js
Normal file
@ -0,0 +1,65 @@
|
||||
// src/services/DataService.js
|
||||
import axios from 'axios';
|
||||
import { io } from 'socket.io-client';
|
||||
|
||||
const API_URL = 'http://localhost:5000/api';
|
||||
const socket = io('http://localhost:5000');
|
||||
|
||||
export const DataService = {
|
||||
// Get all teams
|
||||
getTeams: async () => {
|
||||
try {
|
||||
const response = await axios.get(`${API_URL}/teams`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error fetching teams:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// Add a new team
|
||||
addTeam: async (team) => {
|
||||
try {
|
||||
const response = await axios.post(`${API_URL}/teams`, team);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error adding team:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// Update an existing team
|
||||
updateTeam: async (id, updatedData) => {
|
||||
try {
|
||||
const response = await axios.put(`${API_URL}/teams/${id}`, updatedData);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Error updating team:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// Delete a team
|
||||
deleteTeam: async (id) => {
|
||||
try {
|
||||
await axios.delete(`${API_URL}/teams/${id}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error deleting team:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// Subscribe to real-time updates
|
||||
subscribeToUpdates: (callback) => {
|
||||
socket.on('teams-updated', (updatedTeams) => {
|
||||
callback(updatedTeams);
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off('teams-updated');
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default DataService;
|
||||
5
src/setupTests.js
Normal file
5
src/setupTests.js
Normal file
@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
Loading…
x
Reference in New Issue
Block a user