feat: add membre
This commit is contained in:
@@ -3,6 +3,7 @@ import './AdminRoot.css'
|
||||
import {LoadingProvider} from "../../hooks/useLoading.jsx";
|
||||
import {MemberList} from "../MemberList.jsx";
|
||||
import {MemberPage} from "./member/MemberPage.jsx";
|
||||
import {NewMemberPage} from "./member/NewMemberPage.jsx";
|
||||
|
||||
export function AdminRoot() {
|
||||
return <>
|
||||
@@ -13,7 +14,7 @@ export function AdminRoot() {
|
||||
</>
|
||||
}
|
||||
|
||||
export function getAdminChildren () {
|
||||
export function getAdminChildren() {
|
||||
return [
|
||||
{
|
||||
path: 'member',
|
||||
@@ -23,6 +24,10 @@ export function getAdminChildren () {
|
||||
path: 'member/:id',
|
||||
element: <MemberPage/>
|
||||
},
|
||||
{
|
||||
path: 'member/new',
|
||||
element: <NewMemberPage/>
|
||||
},
|
||||
{
|
||||
path: 'b',
|
||||
element: <div>Admin B</div>
|
||||
|
||||
@@ -5,6 +5,27 @@ import imageCompression from "browser-image-compression";
|
||||
import {BirthDayField, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx";
|
||||
import {ClubSelect} from "../../../components/ClubSelect.jsx";
|
||||
|
||||
export function addPhoto(event, formData, send) {
|
||||
const imageFile = event.target.url_photo.files[0];
|
||||
if (imageFile) {
|
||||
console.log(`originalFile size ${imageFile.size / 1024 / 1024} MB`);
|
||||
|
||||
const options = {
|
||||
maxSizeMB: 1,
|
||||
maxWidthOrHeight: 1920,
|
||||
useWebWorker: true,
|
||||
}
|
||||
|
||||
imageCompression(imageFile, options).then(compressedFile => {
|
||||
console.log(`compressedFile size ${compressedFile.size / 1024 / 1024} MB`); // smaller than maxSizeMB
|
||||
formData.append("photo_data", compressedFile)
|
||||
send(formData)
|
||||
});
|
||||
} else {
|
||||
send(formData)
|
||||
}
|
||||
}
|
||||
|
||||
export function InformationForm({data}) {
|
||||
const setLoading = useLoadingSwitcher()
|
||||
const handleSubmit = (event) => {
|
||||
@@ -25,7 +46,7 @@ export function InformationForm({data}) {
|
||||
formData.append("grade_arbitrage", event.target.grade_arbitrage?.value);
|
||||
|
||||
const send = (formData_) => {
|
||||
apiAxios.post(`/member/${data.id}`, formData_, {
|
||||
apiAxios.put(`/member/${data.id}`, formData_, {
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'multipart/form-data',
|
||||
@@ -40,25 +61,7 @@ export function InformationForm({data}) {
|
||||
setLoading(0)
|
||||
})
|
||||
}
|
||||
|
||||
const imageFile = event.target.url_photo.files[0];
|
||||
if (imageFile) {
|
||||
console.log(`originalFile size ${imageFile.size / 1024 / 1024} MB`);
|
||||
|
||||
const options = {
|
||||
maxSizeMB: 1,
|
||||
maxWidthOrHeight: 1920,
|
||||
useWebWorker: true,
|
||||
}
|
||||
|
||||
imageCompression(imageFile, options).then(compressedFile => {
|
||||
console.log(`compressedFile size ${compressedFile.size / 1024 / 1024} MB`); // smaller than maxSizeMB
|
||||
formData.append("photo_data", compressedFile)
|
||||
send(formData)
|
||||
});
|
||||
} else {
|
||||
send(formData)
|
||||
}
|
||||
addPhoto(event, formData, send);
|
||||
}
|
||||
|
||||
return <form onSubmit={handleSubmit}>
|
||||
|
||||
107
src/main/webapp/src/pages/admin/member/NewMemberPage.jsx
Normal file
107
src/main/webapp/src/pages/admin/member/NewMemberPage.jsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
|
||||
import {apiAxios} from "../../../utils/Tools.js";
|
||||
import {toast} from "react-toastify";
|
||||
import {BirthDayField, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx";
|
||||
import {ClubSelect} from "../../../components/ClubSelect.jsx";
|
||||
import {addPhoto} from "./InformationForm.jsx";
|
||||
|
||||
export function NewMemberPage() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return <>
|
||||
<h2>Page membre</h2>
|
||||
<button type="button" className="btn btn-link" onClick={() => navigate("/admin/member")}>
|
||||
« retour
|
||||
</button>
|
||||
<div>
|
||||
<div className="row">
|
||||
<Form/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
function Form() {
|
||||
const navigate = useNavigate();
|
||||
const setLoading = useLoadingSwitcher()
|
||||
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
setLoading(1)
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("id", -1);
|
||||
formData.append("lname", event.target.lname?.value);
|
||||
formData.append("fname", event.target.fname?.value);
|
||||
formData.append("categorie", event.target.category?.value);
|
||||
formData.append("club", event.target.club?.value);
|
||||
formData.append("genre", event.target.genre?.value);
|
||||
formData.append("country", event.target.country?.value);
|
||||
formData.append("birth_date", new Date(event.target.birth_date?.value).toUTCString());
|
||||
formData.append("email", event.target.email?.value);
|
||||
formData.append("role", event.target.role?.value);
|
||||
formData.append("grade_arbitrage", event.target.grade_arbitrage?.value);
|
||||
|
||||
const send = (formData_) => {
|
||||
apiAxios.post(`/member`, formData_, {
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'multipart/form-data',
|
||||
}
|
||||
}).then(data => {
|
||||
toast.success('Profile crée avec succès 🎉');
|
||||
navigate(`/admin/member/${data.data}`)
|
||||
}).catch(e => {
|
||||
console.log(e.response)
|
||||
toast.error('Échec de la création du profile 😕 (code: ' + e.response.status + ')');
|
||||
}).finally(() => {
|
||||
if (setLoading)
|
||||
setLoading(0)
|
||||
})
|
||||
}
|
||||
|
||||
addPhoto(event, formData, send);
|
||||
}
|
||||
|
||||
return <form onSubmit={handleSubmit}>
|
||||
<div className="card mb-4">
|
||||
<div className="card-header">Nouveau membre</div>
|
||||
<div className="card-body">
|
||||
<TextField name="lname" text="Nom"/>
|
||||
<TextField name="fname" text="Prénom"/>
|
||||
<TextField name="email" text="Email" placeholder="name@example.com"
|
||||
type="email"/>
|
||||
<OptionField name="genre" text="Genre" values={{NA: 'N/A', H: 'H', F: 'F'}}/>
|
||||
<OptionField name="country" text="Pays" value={'fr'}
|
||||
values={{NA: 'Sélectionner...', fr: 'FR', es: 'ES', be: 'BE'}}/>
|
||||
<BirthDayField/>
|
||||
<div className="row">
|
||||
<ClubSelect name="club"/>
|
||||
</div>
|
||||
<OptionField name="role" text="Rôle" value={'MEMBRE'}
|
||||
values={{
|
||||
MEMBRE: 'Membre',
|
||||
PRESIDENT: 'Président',
|
||||
TRESORIER: 'Trésorier',
|
||||
SECRETAIRE: 'Secrétaire'
|
||||
}}/>
|
||||
<OptionField name="grade_arbitrage" text="Grade d'arbitrage" value={'NA'}
|
||||
values={{NA: 'N/A', ASSESSEUR: 'Assesseur', ARBITRE: 'Arbitre'}}/>
|
||||
<div className="row">
|
||||
<div className="input-group mb-3">
|
||||
<label className="input-group-text" htmlFor="url_photo">Photos
|
||||
(optionnelle)</label>
|
||||
<input type="file" className="form-control" id="url_photo" name="url_photo"
|
||||
accept=".jpg,.jpeg,.gif,.png,.svg"/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||
<button type="submit" className="btn btn-primary">Créer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import {LoadingProvider} from "../../hooks/useLoading.jsx";
|
||||
import {MemberPage} from "./member/MemberPage.jsx";
|
||||
import {useAuth} from "../../hooks/useAuth.jsx";
|
||||
import {MemberList} from "../MemberList.jsx";
|
||||
import {NewMemberPage} from "./member/NewMemberPage.jsx";
|
||||
|
||||
export function ClubRoot() {
|
||||
const {userinfo} = useAuth()
|
||||
@@ -35,6 +36,10 @@ export function getClubChildren() {
|
||||
path: 'member/:id',
|
||||
element: <MemberPage/>
|
||||
},
|
||||
{
|
||||
path: 'member/new',
|
||||
element: <NewMemberPage/>
|
||||
},
|
||||
{
|
||||
path: 'b',
|
||||
element: <div>Club B</div>
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
|
||||
import {apiAxios} from "../../../utils/Tools.js";
|
||||
import {toast} from "react-toastify";
|
||||
import imageCompression from "browser-image-compression";
|
||||
import {BirthDayField, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx";
|
||||
import {ClubSelect} from "../../../components/ClubSelect.jsx";
|
||||
import {addPhoto} from "../../admin/member/InformationForm.jsx";
|
||||
|
||||
export function InformationForm({data}) {
|
||||
const setLoading = useLoadingSwitcher()
|
||||
@@ -25,7 +24,7 @@ export function InformationForm({data}) {
|
||||
formData.append("role", event.target.role?.value);
|
||||
|
||||
const send = (formData_) => {
|
||||
apiAxios.post(`/member/club/${data.id}`, formData_, {
|
||||
apiAxios.put(`/member/club/${data.id}`, formData_, {
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'multipart/form-data',
|
||||
@@ -40,23 +39,7 @@ export function InformationForm({data}) {
|
||||
setLoading(0)
|
||||
})
|
||||
}
|
||||
|
||||
const imageFile = event.target.url_photo.files[0];
|
||||
if (imageFile) {
|
||||
console.log(`originalFile size ${imageFile.size / 1024 / 1024} MB`);
|
||||
const options = {
|
||||
maxSizeMB: 1,
|
||||
maxWidthOrHeight: 1920,
|
||||
useWebWorker: true,
|
||||
}
|
||||
imageCompression(imageFile, options).then(compressedFile => {
|
||||
console.log(`compressedFile size ${compressedFile.size / 1024 / 1024} MB`); // smaller than maxSizeMB
|
||||
formData.append("photo_data", compressedFile)
|
||||
send(formData)
|
||||
});
|
||||
} else {
|
||||
send(formData)
|
||||
}
|
||||
addPhoto(event, formData, send);
|
||||
}
|
||||
|
||||
return <form onSubmit={handleSubmit}>
|
||||
@@ -79,7 +62,7 @@ export function InformationForm({data}) {
|
||||
PRESIDENT: 'Président',
|
||||
TRESORIER: 'Trésorier',
|
||||
SECRETAIRE: 'Secrétaire'
|
||||
}}/>
|
||||
}} disabled={true}/>
|
||||
<OptionField name="grade_arbitrage" text="Grade d'arbitrage" value={data.grade_arbitrage}
|
||||
values={{NA: 'N/A', ASSESSEUR: 'Assesseur', ARBITRE: 'Arbitre'}} disabled={true}/>
|
||||
<div className="row">
|
||||
|
||||
92
src/main/webapp/src/pages/club/member/NewMemberPage.jsx
Normal file
92
src/main/webapp/src/pages/club/member/NewMemberPage.jsx
Normal file
@@ -0,0 +1,92 @@
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import {useLoadingSwitcher} from "../../../hooks/useLoading.jsx";
|
||||
import {apiAxios} from "../../../utils/Tools.js";
|
||||
import {toast} from "react-toastify";
|
||||
import {BirthDayField, OptionField, TextField} from "../../../components/MemberCustomFiels.jsx";
|
||||
import {ClubSelect} from "../../../components/ClubSelect.jsx";
|
||||
import {addPhoto} from "../../admin/member/InformationForm.jsx";
|
||||
|
||||
export function NewMemberPage() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return <>
|
||||
<h2>Page membre</h2>
|
||||
<button type="button" className="btn btn-link" onClick={() => navigate("/club/member")}>
|
||||
« retour
|
||||
</button>
|
||||
<div>
|
||||
<div className="row">
|
||||
<Form/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
function Form() {
|
||||
const navigate = useNavigate();
|
||||
const setLoading = useLoadingSwitcher()
|
||||
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
setLoading(1)
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("id", -1);
|
||||
formData.append("lname", event.target.lname?.value);
|
||||
formData.append("fname", event.target.fname?.value);
|
||||
formData.append("categorie", event.target.category?.value);
|
||||
formData.append("genre", event.target.genre?.value);
|
||||
formData.append("country", event.target.country?.value);
|
||||
formData.append("birth_date", new Date(event.target.birth_date?.value).toUTCString());
|
||||
formData.append("email", event.target.email?.value);
|
||||
|
||||
const send = (formData_) => {
|
||||
apiAxios.post(`/member/club`, formData_, {
|
||||
headers: {
|
||||
'Accept': '*/*',
|
||||
'Content-Type': 'multipart/form-data',
|
||||
}
|
||||
}).then(data => {
|
||||
toast.success('Profile crée avec succès 🎉');
|
||||
navigate(`/club/member/${data.data}`)
|
||||
}).catch(e => {
|
||||
console.log(e.response)
|
||||
toast.error('Échec de la création du profile 😕 (code: ' + e.response.status + ')');
|
||||
}).finally(() => {
|
||||
if (setLoading)
|
||||
setLoading(0)
|
||||
})
|
||||
}
|
||||
|
||||
addPhoto(event, formData, send);
|
||||
}
|
||||
|
||||
return <form onSubmit={handleSubmit}>
|
||||
<div className="card mb-4">
|
||||
<div className="card-header">Nouveau membre</div>
|
||||
<div className="card-body">
|
||||
<TextField name="lname" text="Nom"/>
|
||||
<TextField name="fname" text="Prénom"/>
|
||||
<TextField name="email" text="Email" placeholder="name@example.com"
|
||||
type="email"/>
|
||||
<OptionField name="genre" text="Genre" values={{NA: 'N/A', H: 'H', F: 'F'}}/>
|
||||
<OptionField name="country" text="Pays" value={'fr'}
|
||||
values={{NA: 'Sélectionner...', fr: 'FR', es: 'ES', be: 'BE'}}/>
|
||||
<BirthDayField/>
|
||||
<div className="row">
|
||||
<div className="input-group mb-3">
|
||||
<label className="input-group-text" htmlFor="url_photo">Photos
|
||||
(optionnelle)</label>
|
||||
<input type="file" className="form-control" id="url_photo" name="url_photo"
|
||||
accept=".jpg,.jpeg,.gif,.png,.svg"/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="d-grid gap-2 d-md-flex justify-content-md-end">
|
||||
<button type="submit" className="btn btn-primary">Créer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>;
|
||||
}
|
||||
Reference in New Issue
Block a user