minor changes done
This commit is contained in:
parent
1a8a7f21b1
commit
1261906328
|
@ -8,8 +8,14 @@ const Coach = () => {
|
||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
const [editingId, setEditingId] = useState(null);
|
const [editingId, setEditingId] = useState(null);
|
||||||
|
|
||||||
|
// API URL
|
||||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
|
||||||
|
// Coaches SORTED
|
||||||
|
const sortedCoaches = coaches.sort(
|
||||||
|
(a, b) => new Date(b.createdAt) - new Date(a.createdAt)
|
||||||
|
);
|
||||||
|
|
||||||
// Fetch coaches
|
// Fetch coaches
|
||||||
const fetchCoaches = async () => {
|
const fetchCoaches = async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -154,7 +160,7 @@ const Coach = () => {
|
||||||
{/* Coach List */}
|
{/* Coach List */}
|
||||||
<ul className="space-y-4 mt-16">
|
<ul className="space-y-4 mt-16">
|
||||||
<h2 className="text-2xl font-semibold mb-4">Coahes</h2>
|
<h2 className="text-2xl font-semibold mb-4">Coahes</h2>
|
||||||
{coaches.map((coach) => (
|
{sortedCoaches.map((coach) => (
|
||||||
<li
|
<li
|
||||||
key={coach.id}
|
key={coach.id}
|
||||||
className="flex items-center justify-between bg-gray-800 p-4 rounded-lg shadow-md"
|
className="flex items-center justify-between bg-gray-800 p-4 rounded-lg shadow-md"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect, useRef } from "react";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
|
@ -8,7 +8,16 @@ const Events = () => {
|
||||||
const [errorMessage, setErrorMessage] = useState("");
|
const [errorMessage, setErrorMessage] = useState("");
|
||||||
const [editId, setEditId] = useState(null);
|
const [editId, setEditId] = useState(null);
|
||||||
|
|
||||||
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL
|
// reference
|
||||||
|
const dateInputRef = useRef(null);
|
||||||
|
|
||||||
|
// API URL
|
||||||
|
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
|
||||||
|
|
||||||
|
// SORTED EVENTS
|
||||||
|
const sortedEvents = events.sort(
|
||||||
|
(a, b) => new Date(b.createdAt) - new Date(a.createdAt)
|
||||||
|
);
|
||||||
|
|
||||||
// Fetch events
|
// Fetch events
|
||||||
const fetchEvents = async () => {
|
const fetchEvents = async () => {
|
||||||
|
@ -63,13 +72,10 @@ const Events = () => {
|
||||||
if (!validateForm()) return;
|
if (!validateForm()) return;
|
||||||
try {
|
try {
|
||||||
const isoDate = new Date(form.date).toISOString();
|
const isoDate = new Date(form.date).toISOString();
|
||||||
const response = await axios.put(
|
const response = await axios.put(`${API_BASE_URL}/event/${editId}`, {
|
||||||
`${API_BASE_URL}/event/${editId}`,
|
|
||||||
{
|
|
||||||
...form,
|
...form,
|
||||||
date: isoDate,
|
date: isoDate,
|
||||||
}
|
});
|
||||||
);
|
|
||||||
setEvents((prev) =>
|
setEvents((prev) =>
|
||||||
prev.map((event) => (event.id === editId ? response.data.data : event))
|
prev.map((event) => (event.id === editId ? response.data.data : event))
|
||||||
);
|
);
|
||||||
|
@ -121,7 +127,9 @@ const Events = () => {
|
||||||
name="date"
|
name="date"
|
||||||
value={form.date}
|
value={form.date}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
className="px-4 py-2 border rounded-lg bg-gray-800 text-white focus:ring focus:ring-gray-500"
|
ref={dateInputRef}
|
||||||
|
onClick={() => dateInputRef.current.showPicker()}
|
||||||
|
className="px-4 py-2 border rounded-lg bg-gray-800 text-white focus:ring focus:ring-gray-500 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
<textarea
|
<textarea
|
||||||
name="description"
|
name="description"
|
||||||
|
@ -151,7 +159,7 @@ const Events = () => {
|
||||||
{/* Event List */}
|
{/* Event List */}
|
||||||
<ul className="space-y-4 mt-16">
|
<ul className="space-y-4 mt-16">
|
||||||
<h2 className="text-2xl font-semibold mb-4">Events</h2>
|
<h2 className="text-2xl font-semibold mb-4">Events</h2>
|
||||||
{events.map((event) => (
|
{sortedEvents.map((event) => (
|
||||||
<li
|
<li
|
||||||
key={event.id}
|
key={event.id}
|
||||||
className="flex items-center justify-between bg-gray-800 p-4 rounded-lg shadow-md"
|
className="flex items-center justify-between bg-gray-800 p-4 rounded-lg shadow-md"
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { Swiper, SwiperSlide } from "swiper/react";
|
import { Swiper, SwiperSlide } from "swiper/react";
|
||||||
import "swiper/css";
|
import "swiper/css";
|
||||||
|
@ -7,29 +6,33 @@ import { Navigation } from "swiper/modules";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
|
|
||||||
const Hero = () => {
|
const Hero = () => {
|
||||||
const defaultImages = [
|
|
||||||
"/banner1.jpg",
|
|
||||||
"/banner2.jpg",
|
|
||||||
"/banner3.jpg",
|
|
||||||
];
|
|
||||||
|
|
||||||
const [images, setImages] = useState(() => {
|
const [images, setImages] = useState(() => {
|
||||||
|
try {
|
||||||
const savedImages = localStorage.getItem("heroImages");
|
const savedImages = localStorage.getItem("heroImages");
|
||||||
return savedImages ? JSON.parse(savedImages) : defaultImages;
|
return savedImages ? JSON.parse(savedImages) : [];
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error accessing localStorage", error);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save images to localStorage
|
// Save images to localStorage
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
if (images.length > 0) {
|
||||||
|
try {
|
||||||
localStorage.setItem("heroImages", JSON.stringify(images));
|
localStorage.setItem("heroImages", JSON.stringify(images));
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error saving images to localStorage", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}, [images]);
|
}, [images]);
|
||||||
|
|
||||||
// Handle file upload
|
|
||||||
const handleAddImage = (event) => {
|
const handleAddImage = (event) => {
|
||||||
const file = event.target.files[0];
|
const file = event.target.files[0];
|
||||||
if (file) {
|
if (file) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
setImages([...images, e.target.result]);
|
setImages([e.target.result, ...images]);
|
||||||
toast.success("Image added successfully!");
|
toast.success("Image added successfully!");
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
|
@ -58,31 +61,62 @@ const Hero = () => {
|
||||||
|
|
||||||
const handleRemoveImage = (index) => {
|
const handleRemoveImage = (index) => {
|
||||||
const updatedImages = images.filter((_, i) => i !== index);
|
const updatedImages = images.filter((_, i) => i !== index);
|
||||||
setImages(updatedImages.length > 0 ? updatedImages : defaultImages);
|
setImages(updatedImages);
|
||||||
toast.success("Image removed successfully!");
|
toast.success("Image removed successfully!");
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Swiper modules={[Navigation]} navigation loop={true} className="rounded-xl overflow-hidden shadow-lg mb-6" spaceBetween={10} slidesPerView={1}>
|
{images.length > 0 ? (
|
||||||
|
<Swiper
|
||||||
|
modules={[Navigation]}
|
||||||
|
navigation
|
||||||
|
loop={true}
|
||||||
|
spaceBetween={10}
|
||||||
|
slidesPerView={1}
|
||||||
|
>
|
||||||
{images.map((image, index) => (
|
{images.map((image, index) => (
|
||||||
<SwiperSlide key={index} className="relative">
|
<SwiperSlide key={index} className="relative">
|
||||||
<img src={image} alt={`Slide ${index + 1}`} className="w-full lg:h-[600px] md:h-[350px] object-cover" />
|
<img
|
||||||
|
src={image}
|
||||||
|
alt={`Slide ${index + 1}`}
|
||||||
|
className="w-full object-cover h-[300px] md:h-[350px] lg:h-[600px]"
|
||||||
|
/>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<button onClick={() => handleUpdateImage(index)} className="absolute top-4 right-4 bg-blue-500 text-white px-4 py-2 rounded-full hover:bg-blue-600 cursor-pointer">
|
<button
|
||||||
|
onClick={() => handleUpdateImage(index)}
|
||||||
|
className="absolute top-4 right-4 bg-blue-500 text-white px-2 py-1 md:px-4 md:py-2 rounded-full hover:bg-blue-600 cursor-pointer"
|
||||||
|
>
|
||||||
Update
|
Update
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => handleRemoveImage(index)} className="absolute top-4 right-24 bg-red-500 mr-6 text-white px-4 py-2 rounded-full hover:bg-red-600 cursor-pointer">
|
<button
|
||||||
|
onClick={() => handleRemoveImage(index)}
|
||||||
|
className="absolute top-4 right-24 bg-red-500 mr-3 md:mr-6 text-white px-2 py-1 md:px-4 md:py-2 rounded-full hover:bg-red-600 cursor-pointer"
|
||||||
|
>
|
||||||
Remove
|
Remove
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
) : (
|
||||||
|
<p className="text-center text-gray-500 mt-4">
|
||||||
|
No images available. Please add one.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="flex items-center space-x-2 mt-3">
|
<div className="flex items-center space-x-2 mt-3">
|
||||||
<input type="file" accept="image/*" onChange={handleAddImage} className="border border-gray-300 rounded-lg px-3 py-2 w-60 hidden" id="fileInput" />
|
<input
|
||||||
<label htmlFor="fileInput" className="bg-white text-black px-4 py-2 rounded-lg hover:bg-gray-300 cursor-pointer">
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
onChange={handleAddImage}
|
||||||
|
className="hidden"
|
||||||
|
id="fileInput"
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
htmlFor="fileInput"
|
||||||
|
className="bg-white text-black px-4 py-2 rounded-lg hover:bg-gray-300 cursor-pointer"
|
||||||
|
>
|
||||||
Add Image
|
Add Image
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,5 +124,4 @@ const Hero = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default Hero;
|
export default Hero;
|
|
@ -8,8 +8,13 @@ const LoginForm = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const handleLogin = () => {
|
const handleLogin = () => {
|
||||||
const validEmail = process.env.VITE_USERNAME;
|
const validEmail = import.meta.env.VITE_USERNAME;
|
||||||
const validPassword = process.env.VITE_PASSWORD;
|
const validPassword = import.meta.env.VITE_PASSWORD;
|
||||||
|
|
||||||
|
if (!username || !password) {
|
||||||
|
toast.error("Please fill in your credentials.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (username === validEmail && password === validPassword) {
|
if (username === validEmail && password === validPassword) {
|
||||||
toast.success("Login successful!");
|
toast.success("Login successful!");
|
||||||
|
|
Loading…
Reference in a new issue