feat: add keycloak role configuration

This commit is contained in:
2024-01-30 20:04:41 +01:00
parent e3306f4b5a
commit 8824a547bc
7 changed files with 213 additions and 87 deletions

View File

@@ -1,13 +1,13 @@
import {LoadingContextProvider, useLoadingSwitcher} from "../hooks/useLoading.jsx";
import {LoadingProvider, useLoadingSwitcher} from "../hooks/useLoading.jsx";
import {useFetch} from "../hooks/useFetch.js";
import {AxiosError} from "./AxiosError.jsx";
export function ClubSelect({defaultValue, name}) {
return <LoadingContextProvider>
return <LoadingProvider>
<div className="input-group mb-3">
<ClubSelect_ defaultValue={defaultValue} name={name}/>
</div>
</LoadingContextProvider>
</LoadingProvider>
}
function ClubSelect_({defaultValue, name}) {

View File

@@ -13,7 +13,7 @@ export function useLoadingSwitcher() {
return useContext(LoadingSwitcherContext);
}
export function LoadingContextProvider({children}) {
export function LoadingProvider({children}) {
const [showOverlay, setOverlay] = useState(0);
return <LoadingContext.Provider value={showOverlay}>

View File

@@ -1,15 +1,15 @@
import {NavLink, Outlet} from "react-router-dom";
import './AdminRoot.css'
import {LoadingContextProvider} from "../../hooks/useLoading.jsx";
import {LoadingProvider} from "../../hooks/useLoading.jsx";
import {MemberList} from "./MemberList.jsx";
import {MemberPage} from "./MemberPage.jsx";
export function AdminRoot() {
return <>
<h1>Espace administration</h1>
<LoadingContextProvider>
<LoadingProvider>
<Outlet/>
</LoadingContextProvider>
</LoadingProvider>
</>
}

View File

@@ -1,5 +1,5 @@
import {useNavigate, useParams} from "react-router-dom";
import {useLoadingSwitcher} from "../../hooks/useLoading.jsx";
import {LoadingProvider, useLoadingSwitcher} from "../../hooks/useLoading.jsx";
import {useFetch, useFetchPut} from "../../hooks/useFetch.js";
import {AxiosError} from "../../components/AxiosError.jsx";
import {ClubSelect} from "../../components/ClubSelect.jsx";
@@ -18,63 +18,6 @@ export function MemberPage() {
const setLoading = useLoadingSwitcher()
const {data, error} = useFetch(`/member/${id}`, setLoading, 1)
const handleSubmit = (event) => {
event.preventDefault();
setLoading(1)
const formData = new FormData();
formData.append("id", data.id);
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/${id}`, formData_, {
headers: {
'Accept': '*/*',
'Content-Type': 'multipart/form-data',
}
}).then(data => {
console.log(data.data) // TODO
}).catch(e => {
console.log(e.response) // TODO
}).finally(() => {
if (setLoading)
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)
}
}
const handleSubmitPerm = (event) => {
}
return <>
<h2>Page membre</h2>
<button type="button" className="btn btn-link" onClick={() => navigate("/admin/member")}>
@@ -85,11 +28,11 @@ export function MemberPage() {
<div className="row">
<div className="col-lg-4">
<PhotoCard data={data}/>
<CompteInfo userData={data}/>
<LoadingProvider><CompteInfo userData={data}/></LoadingProvider>
</div>
<div className="col-lg-8">
<InformationForm handleSubmit={handleSubmit} data={data}/>
<PremForm handleSubmitPerm={handleSubmitPerm}/>
<InformationForm data={data}/>
<LoadingProvider><PremForm userData={data}/></LoadingProvider>
<div className="row">
<LicenceCard/>
<SelectCard/>
@@ -116,7 +59,62 @@ function PhotoCard({data}) {
</div>;
}
function InformationForm({handleSubmit, data}) {
function InformationForm({data}) {
const setLoading = useLoadingSwitcher()
const handleSubmit = (event) => {
event.preventDefault();
setLoading(1)
const formData = new FormData();
formData.append("id", data.id);
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/${data.id}`, formData_, {
headers: {
'Accept': '*/*',
'Content-Type': 'multipart/form-data',
}
}).then(data => {
toast.success('Profile mis à jours avec succès 🎉');
}).catch(e => {
console.log(e.response)
toast.error('Échec de la mise à jours du profile 😕 (code: ' + e.response.status + ')');
}).finally(() => {
if (setLoading)
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)
}
}
return <form onSubmit={handleSubmit}>
<div className="card mb-4">
<div className="card-header">Information</div>
@@ -161,31 +159,85 @@ function InformationForm({handleSubmit, data}) {
</form>;
}
function PremForm({handleSubmitPerm}) {
function PremForm({userData}) {
const setLoading = useLoadingSwitcher()
const handleSubmitPerm = (event) => {
event.preventDefault();
setLoading(1)
const formData = new FormData();
formData.append("federation_admin", event.target.federation_admin?.checked);
formData.append("safca_user", event.target.safca_user?.checked);
formData.append("safca_create_compet", event.target.safca_create_compet?.checked);
formData.append("safca_super_admin", event.target.safca_super_admin?.checked);
apiAxios.put(`/compte/${userData.userId}/roles`, formData, {
headers: {
'Accept': '*/*',
'Content-Type': 'form-data',
}
}).then(data => {
toast.success('Permission mise à jours avec succès 🎉');
}).catch(e => {
console.log(e.response)
toast.error('Échec de la mise à jours des permissions 😕 (code: ' + e.response.status + ')');
}).finally(() => {
if (setLoading)
setLoading(0)
})
}
return <form onSubmit={handleSubmitPerm}>
<div className="card mb-4">
<div className="card-header">Permission</div>
<div className="card-body">
<div className="row g-3">
<div className="col">
<h5>FFSAF intra</h5>
<CheckField name="federation_admin" text="Accès à l'intra" value={false}/>
</div>
<div className="col">
<h5>SAFCA</h5>
<CheckField name="safca_user" text="Accès à l'application" value={false}/>
<CheckField name="safca_create_compet" text="Créer des compétion" value={false}/>
<CheckField name="safca_super_admin" text="Super administrateur" value={false}/>
</div>
{userData.userId
? <PremFormContent userData={userData}/>
: <div className="col">
<div className="input-group mb-3">
<div>Ce membre ne dispose pas de compte...</div>
</div>
</div>
}
</div>
<div className="row">
<div className="col-md-12 text-right">
<button type="submit" className="btn btn-primary">Enregistrer</button>
{userData.userId && <button type="submit" className="btn btn-primary">Enregistrer</button>}
</div>
</div>
</div>
</div>
</form>;
</form>
}
function PremFormContent({userData}) {
const setLoading = useLoadingSwitcher()
const {data, error} = useFetch(`/compte/${userData.userId}/roles`, setLoading, 1)
return <>
<div className="col">
<h5>FFSAF intra</h5>
{data
? <>
<CheckField name="federation_admin" text="Accès à l'intra"
value={data.includes("federation_admin")}/>
</>
: error && <AxiosError error={error}/>}
</div>
<div className="col">
<h5>SAFCA</h5>
{data
? <>
<CheckField name="safca_user" text="Accès à l'application" value={data.includes("safca_user")}/>
<CheckField name="safca_create_compet" text="Créer des compétion"
value={data.includes("safca_create_compet")}/>
<CheckField name="safca_super_admin" text="Super administrateur"
value={data.includes("safca_super_admin")}/>
</>
: error && <AxiosError error={error}/>}
</div>
</>
}
function LicenceCard() {
@@ -214,12 +266,15 @@ function SelectCard() {
function CompteInfo({userData}) {
const creatAccount = () => {
let err = {};
toast.promise(
apiAxios.put(`/compte/${userData.id}/init`),
apiAxios.put(`/compte/${userData.id}/init`).catch(e => {
err = e
}),
{
pending: 'Création du compte en cours',
success: 'Compte créé avec succès 🎉',
error: 'Échec de la création du compte 😕'
error: 'Échec de la création du compte 😕 (code: ' + err.response.status + ')'
}
)
}
@@ -229,7 +284,8 @@ function CompteInfo({userData}) {
<div className="card-body text-center">
{userData.userId
? <CompteInfoContent userData={userData}/>
: <>
:
<>
<div className="row">
<div className="input-group mb-3">
<div>Ce membre ne dispose pas de compte...</div>
@@ -240,13 +296,16 @@ function CompteInfo({userData}) {
<button className="btn btn-primary" onClick={creatAccount}>Initialiser le compte</button>
</div>
</div>
</>}
</>
}
</div>
</div>
}
function CompteInfoContent({userData}) {
function CompteInfoContent({
userData
}) {
const setLoading = useLoadingSwitcher()
const {data, error} = useFetch(`/compte/${userData.userId}`, setLoading, 1)