310 lines
9.1 KiB
JavaScript
310 lines
9.1 KiB
JavaScript
import { useMemo, useState } from "react";
|
||
import { useNavigate } from "react-router-dom";
|
||
import { motion } from "framer-motion";
|
||
import { FaArrowLeft } from "react-icons/fa";
|
||
import { api } from "../API/api";
|
||
import { useLoading } from "../Context/LoadingContext";
|
||
import Select from 'react-select';
|
||
import canada_cities from '../assets/canada_cities.json';
|
||
|
||
const AddPartner = () => {
|
||
const [uploading, setUploading] = useState(false);
|
||
const [formData, setFormData] = useState({
|
||
name: "",
|
||
open_time: "",
|
||
close_time: "",
|
||
image: null,
|
||
address: "",
|
||
city: "",
|
||
state: "",
|
||
pincode: "",
|
||
screens: "",
|
||
});
|
||
const { setLoading } = useLoading();
|
||
const navigate = useNavigate();
|
||
|
||
const handleChange = (e) => {
|
||
const { name, value } = e.target;
|
||
setFormData({ ...formData, [name]: value });
|
||
};
|
||
|
||
|
||
const handleFileUpload = async (file,id) => {
|
||
if (!file) return;
|
||
|
||
setUploading(true);
|
||
const formData = new FormData();
|
||
formData.append("file", file);
|
||
formData.append("file_name", file.name);
|
||
formData.append("client_id", id); // Attach client ID
|
||
|
||
try {
|
||
console.log(formData)
|
||
setLoading(true)
|
||
await api.post("/files/update-partner-logo", formData, {
|
||
headers: { "Content-Type": "multipart/form-data" },
|
||
});
|
||
navigate("/partners");
|
||
|
||
// Refresh file list after each successful upload
|
||
//fetchFiles();
|
||
} catch (error) {
|
||
console.error(`File upload failed for ${file.name}:`, error);
|
||
// Optionally, you could add some user feedback here for individual file failures
|
||
} finally {
|
||
setUploading(false); // Keep this false, as we're handling individual uploads
|
||
setLoading(false)
|
||
}
|
||
};
|
||
|
||
const handleFileChange = async (e) => {
|
||
|
||
setFormData({ ...formData, image: e.target.files[0] });
|
||
};
|
||
const handleSubmit = async (e) => {
|
||
e.preventDefault();
|
||
try {
|
||
console.log("iuytg")
|
||
setLoading(true);
|
||
var data = await api.post("/admin/add-partner", formData);
|
||
console.log(data)
|
||
console.log("iuytg")
|
||
await handleFileUpload(formData.image,data.id);
|
||
navigate("/Partners");
|
||
} catch (error) {
|
||
console.error("Error adding Partner:", error);
|
||
}
|
||
setLoading(false);
|
||
};
|
||
|
||
const [selectedProvince, setSelectedProvince] = useState(null);
|
||
const [selectedCity, setSelectedCity] = useState(null);
|
||
|
||
const provinceOptions = useMemo(
|
||
() =>
|
||
Object.keys(canada_cities).map((province) => ({
|
||
value: province,
|
||
label: province,
|
||
})),
|
||
[canada_cities]
|
||
);
|
||
|
||
const cityOptions = useMemo(
|
||
() =>
|
||
selectedProvince
|
||
? canada_cities[selectedProvince.value].map((city) => ({
|
||
value: city,
|
||
label: city,
|
||
}))
|
||
: [],
|
||
[selectedProvince, canada_cities]
|
||
);
|
||
|
||
const handleProvinceChange = (selectedOption) => {
|
||
setSelectedProvince(selectedOption);
|
||
setSelectedCity(null);
|
||
setFormData({ ...formData, state: selectedOption?.value || "" }); // Update state in formData
|
||
};
|
||
|
||
const handleCityChange = (selectedOption) => {
|
||
setSelectedCity(selectedOption);
|
||
setFormData({ ...formData, city: selectedOption?.value || "" }); // Update city in formData
|
||
};
|
||
|
||
return (
|
||
<div className="min-h-screen bg-gray-900 text-white p-8">
|
||
<motion.button
|
||
className="mb-4 flex items-center text-gray-400 hover:text-white"
|
||
whileHover={{ scale: 1.1 }}
|
||
onClick={() => navigate("/admin-dashboard")}
|
||
>
|
||
<FaArrowLeft className="mr-2" /> Back
|
||
</motion.button>
|
||
|
||
<motion.h1 className="text-3xl font-bold mb-6">➕ Add New Partner</motion.h1>
|
||
|
||
<form onSubmit={handleSubmit} className="space-y-4">
|
||
<div>
|
||
<label htmlFor="name" className="block text-sm font-medium text-gray-700">
|
||
Partner Name
|
||
</label>
|
||
<input
|
||
type="text"
|
||
name="name"
|
||
id="name"
|
||
placeholder="Partner Name"
|
||
onChange={handleChange}
|
||
className="block w-full bg-gray-700 p-2 rounded-lg mb-2"
|
||
required
|
||
minLength="1"
|
||
maxLength="255"
|
||
/>
|
||
|
||
<label htmlFor="logo_url" className="block text-sm font-medium text-gray-700">
|
||
Logo
|
||
</label>
|
||
<input
|
||
type="file"
|
||
accept="image/*"
|
||
name="logo_url"
|
||
id="logo_url"
|
||
onChange={handleFileChange}
|
||
className="block w-full bg-gray-700 p-2 rounded-lg mb-2"
|
||
/>
|
||
|
||
<label htmlFor="open_time" className="block text-sm font-medium text-gray-700">
|
||
Open Time
|
||
</label>
|
||
<input
|
||
type="time"
|
||
name="open_time"
|
||
id="open_time"
|
||
onChange={handleChange}
|
||
className="block w-full bg-gray-700 p-2 rounded-lg mb-2"
|
||
required
|
||
/>
|
||
|
||
<label htmlFor="close_time" className="block text-sm font-medium text-gray-700">
|
||
Close Time
|
||
</label>
|
||
<input
|
||
type="time"
|
||
name="close_time"
|
||
id="close_time"
|
||
onChange={handleChange}
|
||
className="block w-full bg-gray-700 p-2 rounded-lg mb-2"
|
||
required
|
||
/>
|
||
|
||
<label htmlFor="address" className="block text-sm font-medium text-gray-700">
|
||
Address
|
||
</label>
|
||
<input
|
||
type="text"
|
||
name="address"
|
||
id="address"
|
||
placeholder="Address"
|
||
onChange={handleChange}
|
||
className="block w-full bg-gray-700 p-2 rounded-lg mb-2"
|
||
required
|
||
/>
|
||
|
||
<label htmlFor="state" className="block text-sm font-medium text-gray-700">
|
||
Province
|
||
</label>
|
||
<Select
|
||
options={provinceOptions}
|
||
value={selectedProvince}
|
||
onChange={handleProvinceChange}
|
||
isSearchable
|
||
className="block w-full mb-2"
|
||
styles={{
|
||
control: (provided) => ({
|
||
...provided,
|
||
backgroundColor: '#374151',
|
||
color: 'white',
|
||
borderRadius: '0.5rem',
|
||
padding: '0.5rem',
|
||
border: 'none',
|
||
}),
|
||
option: (provided, state) => ({
|
||
...provided,
|
||
backgroundColor: state.isSelected ? '#1f2937' : '#374151',
|
||
color: 'white',
|
||
}),
|
||
singleValue: (provided) => ({
|
||
...provided,
|
||
color: 'white',
|
||
}),
|
||
input: (provided) => ({
|
||
...provided,
|
||
color: 'white',
|
||
}),
|
||
placeholder: (provided) => ({
|
||
...provided,
|
||
color: 'white',
|
||
}),
|
||
}}
|
||
placeholder="Select Province"
|
||
/>
|
||
|
||
<label htmlFor="city" className="block text-sm font-medium text-gray-700">
|
||
City
|
||
</label>
|
||
<Select
|
||
options={cityOptions}
|
||
value={selectedCity}
|
||
onChange={handleCityChange}
|
||
isSearchable
|
||
className="block w-full mb-2"
|
||
styles={{
|
||
control: (provided) => ({
|
||
...provided,
|
||
backgroundColor: '#374151',
|
||
color: 'white',
|
||
borderRadius: '0.5rem',
|
||
padding: '0.5rem',
|
||
border: 'none',
|
||
}),
|
||
option: (provided, state) => ({
|
||
...provided,
|
||
backgroundColor: state.isSelected ? '#1f2937' : '#374151',
|
||
color: 'white',
|
||
}),
|
||
singleValue: (provided) => ({
|
||
...provided,
|
||
color: 'white',
|
||
}),
|
||
input: (provided) => ({
|
||
...provided,
|
||
color: 'white',
|
||
}),
|
||
placeholder: (provided) => ({
|
||
...provided,
|
||
color: 'white',
|
||
}),
|
||
}}
|
||
placeholder="Select City"
|
||
isDisabled={!selectedProvince}
|
||
/>
|
||
|
||
<label htmlFor="pincode" className="block text-sm font-medium text-gray-700">
|
||
Pincode
|
||
</label>
|
||
<input
|
||
type="text"
|
||
name="pincode"
|
||
id="pincode"
|
||
placeholder="Pincode"
|
||
onChange={handleChange}
|
||
className="block w-full bg-gray-700 p-2 rounded-lg mb-2"
|
||
required
|
||
/>
|
||
|
||
<label htmlFor="screens" className="block text-sm font-medium text-gray-700">
|
||
No. of. Screens
|
||
</label>
|
||
<input
|
||
type="number"
|
||
name="screens"
|
||
id="screens"
|
||
placeholder="No. of. Screens"
|
||
onChange={handleChange}
|
||
className="block w-full bg-gray-700 p-2 rounded-lg mb-2"
|
||
required
|
||
min="1"
|
||
/>
|
||
</div>
|
||
<motion.button
|
||
type="submit"
|
||
className="bg-blue-500 px-4 py-2 rounded-lg"
|
||
whileHover={{ scale: 1.05 }}
|
||
>
|
||
Submit
|
||
</motion.button>
|
||
</form>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default AddPartner; |