01/04/24 - 23h30

recette2
cherif 2024-04-01 23:25:46 +02:00
parent 3b269cd25a
commit efd59b4a3b
4 changed files with 1369 additions and 9 deletions

View File

@ -53,6 +53,7 @@ import { gridClasses } from '@mui/x-data-grid';
import Link from '@mui/material/Link';
import { PiDotsThree } from "react-icons/pi";
import { IoAddCircleOutline, IoCloseCircleOutline } from "react-icons/io5";
import Rating from '@mui/material/Rating';
const Employes = (props) => {
const history = useHistory();
@ -799,6 +800,7 @@ const Employes = (props) => {
Get_List_Managers();
Get_List_RH_Profils();
Get_Employee_Related_Target_Collection_Data();
Get_List_Competence_Type();
Get_Partner_Object_Specific_Fields("ressource_humaine");
@ -1045,6 +1047,9 @@ const Employes = (props) => {
const [employee_data_edit_mode, setemployee_data_edit_mode] = useState("");
const [employee_list_competence, setemployee_list_competence] = useState([]);
const [GetAttendee_api, setGetAttendee_api] = useState();
const [GetAttendee_message, setGetAttendee_message] = useState();
const [GetAttendee_result, setGetAttendee_result] = useState();
@ -1096,6 +1101,13 @@ const Employes = (props) => {
}
if (mylocal_employe.list_competence) {
setemployee_list_competence(mylocal_employe.list_competence);
} else {
setemployee_list_competence([]);
}
if (mylocal_employe.telephone_mobile) {
setp_detail_tel_mobile(mylocal_employe.telephone_mobile);
} else {
@ -2386,6 +2398,85 @@ const Employes = (props) => {
}
const [New_Get_List_Competence_Type_result, setNew_Get_List_Competence_Type_result] = useState();
const [Get_List_Competence_Type_api, setGet_List_Competence_Type_api] = useState();
const [Get_List_Competence_Type_message, setGet_List_Competence_Type_message] = useState();
const [Get_List_Competence_Type_result, setGet_List_Competence_Type_result] = useState();
function Get_List_Competence_Type(event) {
var form = new FormData();
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Competence_Level/";
axios.post(myurl, form).then(res => {
//console.log(" In Get_List_Competence_Type res.data.status = " + res.data.status);
//console.log(" In Get_List_Competence_Type res.data.message r_class = " + res.data.message);
if (String(res.data.status) === String("true")) {
setGet_List_Competence_Type_api("true");
setGet_List_Competence_Type_result(res.data.message);
var new_data2 = [];
const new_data = res.data.message.map((x) => {
//---
var localid = JSON.parse(x).id;
var local_id = JSON.parse(x)._id;
var local_code = JSON.parse(x).code;
var local_note = JSON.parse(x).note;
//---
var node = {
"_id": local_id,
"id": localid,
"label": local_code,
"code": local_code,
"note": local_note,
};
new_data2.push(node);
});
var node = {
"_id": "",
"id": "",
"label": "",
"code": "",
"note": "",
};
//console.log(" ### new_data2 = ", new_data2);
new_data2.push(node);
if (new_data2.length > 0) {
setNew_Get_List_Competence_Type_result(new_data2);
}
}
else if (String(res.data.status) === String("Err_Connexion")) {
alert('Erreur: ' + res.data.message);
history.push("/Connexion");
}
else {
setGet_List_Competence_Type_api("false");
setGet_List_Competence_Type_message(res.data.message);
}
}).catch((error) => {
console.warn('Not good man :( Get_List_Competence_Type = ', error);
setGet_List_Competence_Type_api("false");
//setmyApimyApiMessage("")
})
}
const [field_competence, setfield_competence] = useState("");
const [field_one_competence, setfield_one_competence] = useState("");
@ -2850,9 +2941,7 @@ const Employes = (props) => {
setsubmenu("detail_employe");
await sleep(5);
/*if (!edit_session_form) {
desableSessionFields();
}*/
if (document.getElementById("detail_employe")) {
document.getElementById("detail_employe").style.backgroundColor = "#104277";
@ -2874,6 +2963,18 @@ const Employes = (props) => {
document.getElementById("contrat").style.color = "black";
}
if (document.getElementById("competence")) {
document.getElementById("competence").style.backgroundColor = "#d8edfc";
document.getElementById("competence").style.color = "black";
}
if (document.getElementById("piece_jointe")) {
document.getElementById("piece_jointe").style.backgroundColor = "#d8edfc";
document.getElementById("piece_jointe").style.color = "black";
}
//console.log(" ### employee_data_edit_mode = ", employee_data_edit_mode);
if (String(employee_data_edit_mode) !== "1")
disable_Employee_DetailFields();
@ -2916,6 +3017,16 @@ const Employes = (props) => {
}
if (document.getElementById("competence")) {
document.getElementById("competence").style.backgroundColor = "#d8edfc";
document.getElementById("competence").style.color = "black";
}
if (document.getElementById("piece_jointe")) {
document.getElementById("piece_jointe").style.backgroundColor = "#d8edfc";
document.getElementById("piece_jointe").style.color = "black";
}
}
async function submenu_contrat() {
@ -2942,6 +3053,18 @@ const Employes = (props) => {
document.getElementById("droit_acces").style.color = "black";
}
if (document.getElementById("competence")) {
document.getElementById("competence").style.backgroundColor = "#d8edfc";
document.getElementById("competence").style.color = "black";
}
if (document.getElementById("piece_jointe")) {
document.getElementById("piece_jointe").style.backgroundColor = "#d8edfc";
document.getElementById("piece_jointe").style.color = "black";
}
}
@ -2971,6 +3094,18 @@ const Employes = (props) => {
document.getElementById("contrat").style.color = "black";
}
if (document.getElementById("competence")) {
document.getElementById("competence").style.backgroundColor = "#d8edfc";
document.getElementById("competence").style.color = "black";
}
if (document.getElementById("piece_jointe")) {
document.getElementById("piece_jointe").style.backgroundColor = "#d8edfc";
document.getElementById("piece_jointe").style.color = "black";
}
setSelectionModel_affectations([]);
setdisplay_affectation("0");
setAdd_new_affectation("");
@ -2979,6 +3114,84 @@ const Employes = (props) => {
}
async function submenu_competence() {
setsubmenu("competence");
//await sleep(5);
if (document.getElementById("competence")) {
document.getElementById("competence").style.backgroundColor = "#104277";
document.getElementById("competence").style.color = "white";
}
if (document.getElementById("piece_jointe")) {
document.getElementById("piece_jointe").style.backgroundColor = "#d8edfc";
document.getElementById("piece_jointe").style.color = "black";
}
if (document.getElementById("contrat")) {
document.getElementById("contrat").style.backgroundColor = "#d8edfc";
document.getElementById("contrat").style.color = "black";
}
if (document.getElementById("affectation")) {
document.getElementById("affectation").style.backgroundColor = "#d8edfc";
document.getElementById("affectation").style.color = "black";
}
if (document.getElementById("detail_employe")) {
document.getElementById("detail_employe").style.backgroundColor = "#d8edfc";
document.getElementById("detail_employe").style.color = "black";
}
if (document.getElementById("droit_acces")) {
document.getElementById("droit_acces").style.backgroundColor = "#d8edfc";
document.getElementById("droit_acces").style.color = "black";
}
Getall_Partner_Competence_List();
}
async function submenu_piece_jointe() {
setsubmenu("piece_jointe");
await sleep(5);
if (document.getElementById("piece_jointe")) {
document.getElementById("piece_jointe").style.backgroundColor = "#104277";
document.getElementById("piece_jointe").style.color = "white";
}
if (document.getElementById("competence")) {
document.getElementById("competence").style.backgroundColor = "#d8edfc";
document.getElementById("competence").style.color = "black";
}
if (document.getElementById("contrat")) {
document.getElementById("contrat").style.backgroundColor = "#d8edfc";
document.getElementById("contrat").style.color = "black";
}
if (document.getElementById("affectation")) {
document.getElementById("affectation").style.backgroundColor = "#d8edfc";
document.getElementById("affectation").style.color = "black";
}
if (document.getElementById("detail_employe")) {
document.getElementById("detail_employe").style.backgroundColor = "#d8edfc";
document.getElementById("detail_employe").style.color = "black";
}
if (document.getElementById("droit_acces")) {
document.getElementById("droit_acces").style.backgroundColor = "#d8edfc";
document.getElementById("droit_acces").style.color = "black";
}
}
async function submenu_droit_acces_orig() {
/***
@ -3024,6 +3237,85 @@ const Employes = (props) => {
}
const [New_Getall_Partner_Competence_List_result, setNew_Getall_Partner_Competence_List_result] = useState([]);
const [Getall_Partner_Competence_List_api, setGetall_Partner_Competence_List_api] = useState();
const [Getall_Partner_Competence_List_message, setGetall_Partner_Competence_List_message] = useState();
const [Getall_Partner_Competence_List_result, setGetall_Partner_Competence_List_result] = useState([]);
function Getall_Partner_Competence_List(event) {
var form = new FormData();
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Competence_no_filter/";
setLoading(true);
axios.post(myurl, form).then(res => {
setLoading(false);
if (String(res.data.status) === String("true")) {
//console.log(" In Getall_Partner_Competence_List res.data.status = " + res.data.status);
//console.log(" In Getall_Partner_Competence_List res.data.message r_class = " + res.data.message);
setGetall_Partner_Competence_List_api("true");
setGetall_Partner_Competence_List_result(res.data.message);
var new_data2 = [];
const new_data = res.data.message.map((x) => {
//---
var localid = JSON.parse(x).id;
var local_id = JSON.parse(x)._id;
var local_description = JSON.parse(x).description;
//---
var node = {
"_id": local_id,
"id": localid,
"label": local_description,
"description": local_description,
};
new_data2.push(node);
});
//---
var node = {
"_id": "",
"id": "",
"label": "",
"code": "",
"description": "",
"rang": "",
};
new_data2.push(node);
if (new_data2.length > 0)
setNew_Getall_Partner_Competence_List_result(new_data2);
}
else {
setGetall_Partner_Competence_List_api("false");
setGetall_Partner_Competence_List_message(res.data.message);
alert(res.data.message);
}
}).catch((error) => {
setLoading(false);
console.warn('Not good man :( Getall_Partner_Competence_List = ', error);
setGetall_Partner_Competence_List_api("false");
alert(" Impossible de recuperer la liste des compétences ");
//setmyApimyApiMessage("")
})
}
const New_Option_Oui_Non = [
{
value: '1',
@ -4785,6 +5077,92 @@ const Employes = (props) => {
{ "id": "", "label": "", "value": "" },
]
const [Dialog_1_open_competence, setDialog_1_open_competence] = React.useState(false);
const [Dialog_1_message_competence, setDialog_1_message_competence] = React.useState("Gestion compétences");
const Dialog_1_handleClose_buton_competence = () => {
};
const Dialog_1_handle_OK_buton_competence = () => {
setDialog_1_open_competence(false);
};
const Dialog_1_handleCancel_buton_competence = () => {
setDialog_1_open_competence(false);
};
const [detail_competence_code, setdetail_competence_code] = React.useState("");
const [detail_competence_niveau, setdetail_competence_niveau] = React.useState("");
const [selected_competence_id, setselected_competence_id] = React.useState("");
const [Add_Update_One_Competence_api, setAdd_Update_One_Competence_api] = useState();
const [Add_Update_One_Competence_message, setAdd_Update_One_Competence_message] = useState();
const [Add_Update_One_Competence_result, setAdd_Update_One_Competence_result] = useState();
const Add_Update_One_Competence = event => {
if (String(selected_id).length < 2) {
alert(" Vous devez choisir un employé ");
return;
}
var form = new FormData();
//form.append("token","K3cw63eKokKSbV4spjQ48SUNnfy80yrXfA");
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
form.append("rh_id", selected_id);
form.append("competence_id", selected_competence_id);
form.append("competence", detail_competence_code);
form.append("niveau", detail_competence_niveau);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Add_Update_RH_Competence/";
setLoading(true);
axios.post(myurl, form).then(res => {
//console.log(" In Add_Update_One_Competence res.data.status = " + res.data.status);
//console.log(" In Add_Update_One_Competence res.data.message r_class = " + res.data.message);
setLoading(false);
if (String(res.data.status) === String("true")) {
setAdd_Update_One_Competence_api("true");
setAdd_Update_One_Competence_result(res.data.message);
setdetail_competence_code("");
setdetail_competence_niveau("");
setselected_competence_id("");
Get_Employee_Data(selected_id);
alert(res.data.message);
setDialog_1_open_competence(false);
}
else {
setAdd_Update_One_Competence_api("false");
setAdd_Update_One_Competence_message(res.data.message);
alert(res.data.message);
}
}).catch((error) => {
setLoading(false);
console.warn('UpdateStagiaireData : Not good man :( Add_Update_One_Competence = ' + error);
setAdd_Update_One_Competence_api("false");
alert(" Impossible de mettre à jour la compétence ");
})
}
return (
<div className="employes">
@ -4792,6 +5170,117 @@ const Employes = (props) => {
<div className="mysy_spinner"> <img src={img_loading_spin} /> </div>
</div>}
{/*** GESTION COMPETENCES */}
<Dialog
open={Dialog_1_open_competence}
onClose={Dialog_1_handleClose_buton_competence}
className="displaypartnersession"
>
<DialogTitle>MySy Information</DialogTitle>
<DialogContent className="DialogContent_width" style={{ "minHeight": "15rem" }}>
<div className="session_caract_Dialog" > Compétence
{New_Getall_Partner_Competence_List_result && New_Getall_Partner_Competence_List_result.length > 0 && detail_competence_code &&
String(detail_competence_code).length > 2 &&
<Autocomplete
disablePortal
id="competence_nom"
name="competence_nom"
fullWidth
options={New_Getall_Partner_Competence_List_result}
value={New_Getall_Partner_Competence_List_result.filter((data) => (data).description === String(detail_competence_code))[0].description}
onChange={(event, value) => {
if (value && value._id) {
setdetail_competence_code(value.code);
} else {
setdetail_competence_code("");
}
}}
renderInput={(params) => <TextField {...params} label="" placeholder="Choisir une option"
inputProps={{ ...params.inputProps, style: { fontSize: 12, height: "1.4rem" } }}
/>
}
/>}
{/*<TextField
autoFocus
margin="dense"
id="competence_nom"
name="competence_nom"
fullWidth
//variant="standard"
value={detail_competence_code}
onChange={(e) => {
setdetail_competence_code(e.target.value);
}
}
/> */}
</div>
<div className="session_caract_Dialog" > Niveau Compétence
{New_Get_List_Competence_Type_result && New_Get_List_Competence_Type_result.length > 0 && detail_competence_niveau &&
String(detail_competence_niveau).length > 2 &&
<Autocomplete
disablePortal
id="niveau_competence_nom"
name="niveau_competence_nom"
fullWidth
options={New_Get_List_Competence_Type_result}
value={New_Get_List_Competence_Type_result.filter((data) => (data).code === String(detail_competence_niveau))[0].code}
onChange={(event, value) => {
if (value && value._id) {
setdetail_competence_niveau(value.code);
} else {
setdetail_competence_niveau("");
}
}}
renderInput={(params) => <TextField {...params} label="" placeholder="Choisir une option"
inputProps={{ ...params.inputProps, style: { fontSize: 12, height: "1.4rem" } }}
/>
}
/>}
</div>
</DialogContent>
<DialogActions>
<div className="div_row">
{String(selected_competence_id) === "" && <div className="div_row_gauche"> <Button onClick={Add_Update_One_Competence} className="bton_enreg_dialog">Ajouter</Button> </div>}
{String(selected_competence_id) !== "" && <div className="div_row_gauche"> <Button onClick={Add_Update_One_Competence} className="bton_enreg_dialog">Mettre à jour</Button> </div>}
<div className="div_row_droite" style={{ "textAlign": 'center' }}>
<Button onClick={Dialog_1_handleCancel_buton_competence} className="bton_annule_dialog" >Fermer</Button>
</div>
</div>
</DialogActions>
</Dialog>
{/*** FIN GESTION COMPETENCES */}
<Dialog
open={Dialog_employe_open}
@ -5919,6 +6408,7 @@ const Employes = (props) => {
get_Employee_Images(newSelectionModel.row._id);
setgridline_id(newSelectionModel.row.id);
if (newSelectionModel.row.date_naissance) {
var local_date_naissance = newSelectionModel.row.date_naissance;
var date_eval = new Date(moment(local_date_naissance, "DD/MM/YYYY"));
@ -6055,9 +6545,12 @@ const Employes = (props) => {
{String(submenu) === "detail_employe" && String(add_One_Employee) !== "1" && <div className="div_row">
<div className="div_row">
<Button variant="outlined" onClick={submenu_detail_employe} className="detail_class_submenu" id='detail_employe' name='detail_employe'>Détail employé</Button>
<Button variant="outlined" onClick={submenu_competence} className="detail_class_submenu" id='competence' name='contrat'>Compétences </Button>
<Button variant="outlined" onClick={submenu_piece_jointe} className="detail_class_submenu" id='piece_jointe' name='contrat'>Pièces Jointes </Button>
<Button variant="outlined" onClick={submenu_droit_acces} className="detail_class_submenu" id='droit_acces' name='droit_acces'>Droits d'accès </Button>
<Button variant="outlined" onClick={submenu_affectation} className="detail_class_submenu" id='affectation' name='affectation'>Affectation </Button>
<Button variant="outlined" onClick={submenu_contrat} className="detail_class_submenu" id='affectation' name='contrat'>Contrat </Button>
</div>
<nav style={{ "border": "None", "fontSize": "22px", "fontWeight": "600" }}> Détail Employé </nav>
@ -7235,9 +7728,14 @@ const Employes = (props) => {
{String(submenu) === "detail_employe" && String(add_One_Employee) === "1" && <div className="div_row">
<div className="div_row">
<Button variant="outlined" onClick={submenu_detail_employe} className="detail_class_submenu" id='detail_employe' name='detail_employe'>Détail employé</Button>
<Button variant="outlined" onClick={submenu_competence} className="detail_class_submenu" id='competence' name='contrat'>Compétences </Button>
<Button variant="outlined" onClick={submenu_piece_jointe} className="detail_class_submenu" id='piece_jointe' name='contrat'>Pièces Jointes </Button>
<Button variant="outlined" onClick={submenu_droit_acces} className="detail_class_submenu" id='droit_acces' name='droit_acces'>Droits d'accès </Button>
<Button variant="outlined" onClick={submenu_affectation} className="detail_class_submenu" id='affectation' name='affectation'>Affectation </Button>
<Button variant="outlined" onClick={submenu_contrat} className="detail_class_submenu" id='affectation' name='contrat'>Contrat </Button>
</div>
<nav style={{ "border": "None", "fontSize": "22px", "fontWeight": "600" }}> Ajouter un Employé </nav>
@ -7667,13 +8165,13 @@ const Employes = (props) => {
placeholder='Message'
onChange={(e) => {
setfield_one_competence(e.target.value);
}}
></textarea>
</div>}
=
=
</div>
@ -7770,6 +8268,8 @@ const Employes = (props) => {
{String(submenu) === "affectation" && <div className="div_row" style={{ paddingRight: '10px' }}>
<div className="div_row">
<Button variant="outlined" onClick={submenu_detail_employe} className="detail_class_submenu" id='detail_employe' name='detail_employe'>Détail employé</Button>
<Button variant="outlined" onClick={submenu_competence} className="detail_class_submenu" id='competence' name='contrat'>Compétences </Button>
<Button variant="outlined" onClick={submenu_piece_jointe} className="detail_class_submenu" id='piece_jointe' name='contrat'>Pièces Jointes </Button>
<Button variant="outlined" onClick={submenu_droit_acces} className="detail_class_submenu" id='droit_acces' name='droit_acces'>Droits d'accès </Button>
<Button variant="outlined" onClick={submenu_affectation} className="detail_class_submenu" id='affectation' name='affectation'>Affectation </Button>
<Button variant="outlined" onClick={submenu_contrat} className="detail_class_submenu" id='affectation' name='contrat'>Contrat </Button>
@ -7889,7 +8389,7 @@ const Employes = (props) => {
<Button variant="outlined" onClick={add_one_affectation_block}
className="detail_class_submenu bton_add_session"
id='menu_add_participant' name='menu_add_participant'>Ajout 1 affectation &nbsp;
id='menu_add_participant' name='menu_add_participant'>Ajout affectation
<IoAddCircleOutline style={{ "fontSize": "x-large", "color": "green" }} />
</Button>
@ -8332,6 +8832,8 @@ const Employes = (props) => {
<nav style={{ "border": "None", "fontSize": "22px", "fontWeight": "600" }}> Droits accès </nav>
<div className="div_row">
<Button variant="outlined" onClick={submenu_detail_employe} className="detail_class_submenu" id='detail_employe' name='detail_employe'>Détail employé</Button>
<Button variant="outlined" onClick={submenu_competence} className="detail_class_submenu" id='competence' name='contrat'>Compétences </Button>
<Button variant="outlined" onClick={submenu_piece_jointe} className="detail_class_submenu" id='piece_jointe' name='contrat'>Pièces Jointes </Button>
<Button variant="outlined" onClick={submenu_droit_acces} className="detail_class_submenu" id='droit_acces' name='droit_acces'>Droits d'accès </Button>
<Button variant="outlined" onClick={submenu_affectation} className="detail_class_submenu" id='affectation' name='affectation'>Affectation </Button>
<Button variant="outlined" onClick={submenu_contrat} className="detail_class_submenu" id='affectation' name='contrat'>Contrat </Button>
@ -8577,6 +9079,8 @@ const Employes = (props) => {
<nav style={{ "border": "None", "fontSize": "22px", "fontWeight": "600" }}> Detail contrat(s) </nav>
<div className="div_row">
<Button variant="outlined" onClick={submenu_detail_employe} className="detail_class_submenu" id='detail_employe' name='detail_employe'>Détail employé</Button>
<Button variant="outlined" onClick={submenu_competence} className="detail_class_submenu" id='competence' name='contrat'>Compétences </Button>
<Button variant="outlined" onClick={submenu_piece_jointe} className="detail_class_submenu" id='piece_jointe' name='contrat'>Pièces Jointes </Button>
<Button variant="outlined" onClick={submenu_droit_acces} className="detail_class_submenu" id='droit_acces' name='droit_acces'>Droits d'accès </Button>
<Button variant="outlined" onClick={submenu_affectation} className="detail_class_submenu" id='affectation' name='affectation'>Affectation </Button>
<Button variant="outlined" onClick={submenu_contrat} className="detail_class_submenu" id='affectation' name='contrat'>Contrat </Button>
@ -8681,6 +9185,233 @@ const Employes = (props) => {
</div>
}
{String(submenu) === "piece_jointe" && <div className="div_row" style={{ paddingRight: '10px' }}>
<div className="div_row">
<Button variant="outlined" onClick={submenu_detail_employe} className="detail_class_submenu" id='detail_employe' name='detail_employe'>Détail employé</Button>
<Button variant="outlined" onClick={submenu_competence} className="detail_class_submenu" id='competence' name='contrat'>Compétences </Button>
<Button variant="outlined" onClick={submenu_piece_jointe} className="detail_class_submenu" id='piece_jointe' name='contrat'>Pièces Jointes </Button>
<Button variant="outlined" onClick={submenu_droit_acces} className="detail_class_submenu" id='droit_acces' name='droit_acces'>Droits d'accès </Button>
<Button variant="outlined" onClick={submenu_affectation} className="detail_class_submenu" id='affectation' name='affectation'>Affectation </Button>
<Button variant="outlined" onClick={submenu_contrat} className="detail_class_submenu" id='affectation' name='contrat'>Contrat </Button>
</div>
<nav style={{ "border": "None", "fontSize": "22px", "fontWeight": "600" }}> Les pièces jointes </nav>
<div className="session_data">
<br />
<div className="div_row">
<div className="div_row" style={{ "padding": "5px" }}>
<div style={{ "fontSize": "12px" }}>
<label htmlFor="upload-photo">
<input
style={{ display: "none" }}
id="upload-photo"
name="upload-photo"
type="file"
onChange={sessions_file_change_1}
/>
<Fab
color="secondary"
size="small"
component="span"
aria-label="add"
variant="extended"
>
<IoMdAddCircle /> <nav style={{ "fontSize": "12px" }}> Ajouter un fichier </nav>
</Fab>
</label>
</div>
{file_1_name && file_1_name.name &&
<nav style={{ "fontSize": "12px" }}>
<div className="session_caract">Nom du fichier <br />
<TextField
name="file_to_download_type_name"
id="file_to_download_type_name"
InputLabelProps={{
shrink: true,
}}
disabled={false}
className="disabled_style enable_style"
value={p_detail_one_file_to_download_type_name}
onChange={(e) => {
setp_detail_one_file_to_download_type_name(e.target.value);
}}
/>
</div>
<br />
<br />
Fichier : {file_1_name.name} <br /> <font style={{ "cursor": "pointer" }}
onClick={Delete_file_1_name}> Supprimer <IoIosRemoveCircleOutline /> </font>
</nav>}
{Record_All_PJ_api && String(Record_All_PJ_api) === "true" && <div className="okUpdateData"> Pièce jointe enregistrée </div>}
{Record_All_PJ_api && String(Record_All_PJ_api) === "false" && <div className="koUpdateData"> {Record_All_PJ_message} </div>}
</div>
{file_1_name && file_1_name.name && <div className="div_row">
<div className="div_row_gauche">
<Button variant="contained" onClick={Record_All_PJ}
startIcon={<AiTwotoneSave />} className="bton_enreg">ENREGISTRER LA PIECE</Button>
</div>
</div>}
{Get_List_Of_All_PJ_result && <div className="div_row" style={{ "padding": "5px" }}>
<div className="div_row">
Liste des pièces jointes <br />
<div className="div_row">
{Get_List_Of_All_PJ_result && Get_List_Of_All_PJ_result.map((val) => (
<div className="div_row_list_pj" >
<nav style={{ "color": "green", "cursor": "pointer" }} onClick={Download_one_attached_document} name={(JSON.parse(val).file_name)} id={(JSON.parse(val).file_name)}> Télécharger &nbsp;<i> {(JSON.parse(val).file_business_object)}</i> </nav> <br />
<Popup
trigger={
<nav style={{ "color": "red", "cursor": "pointer" }} > Supprimer</nav>
}
modal
nested
position="center center"
>
{close => (
<div>
<button className="gest_close" onClick={close}>
&times;
</button>
<div className="gest_header"> MySy Information </div>
<div className="gest_content">
{' '}
En confirmant cette opération, la pièce jointe sera <i><font color="red"> définitivement supprimée</font></i>. <br />
</div>
<div className="gest_actions">
<div style={{ "width": "45%", "float": "left" }}>
<button className="gest_bton_popup" onClick={(event) => {
Delete_one_attached_document(event);
close();
}}
name={(JSON.parse(val).file_name)} id={(JSON.parse(val).file_name)}
> Valider </button>
</div>
<div style={{ "width": "45%", "float": "right" }}>
<button
className="gest_bton_popup"
onClick={() => {
//console.log('modal closed ');
close();
}}
>
Annuler
</button>
</div>
</div>
</div>
)}
</Popup>
</div>
))}
</div>
</div>
</div>}
</div>
<div className="div_row" style={{ "border": "None" }}>
&nbsp;
</div>
</div>
</div>}
{String(submenu) === "competence" && <div className="div_row" style={{ paddingRight: '10px' }}>
<div className="div_row">
<Button variant="outlined" onClick={submenu_detail_employe} className="detail_class_submenu" id='detail_employe' name='detail_employe'>Détail employé</Button>
<Button variant="outlined" onClick={submenu_competence} className="detail_class_submenu" id='competence' name='contrat'>Compétences </Button>
<Button variant="outlined" onClick={submenu_piece_jointe} className="detail_class_submenu" id='piece_jointe' name='contrat'>Pièces Jointes </Button>
<Button variant="outlined" onClick={submenu_droit_acces} className="detail_class_submenu" id='droit_acces' name='droit_acces'>Droits d'accès </Button>
<Button variant="outlined" onClick={submenu_affectation} className="detail_class_submenu" id='affectation' name='affectation'>Affectation </Button>
<Button variant="outlined" onClick={submenu_contrat} className="detail_class_submenu" id='affectation' name='contrat'>Contrat </Button>
</div>
<nav style={{ "border": "None", "fontSize": "22px", "fontWeight": "600" }}> Les Compétences </nav>
<div className="session_data" style={{ "minHeight": '15rem', "paddingLeft": "10px", "paddingRight": "10px" }}>
<br />
{employee_list_competence && employee_list_competence.map((competence) => (
<nav className="block_competence">
<nav recid={competence.niveau} onClick={(event) => {
setdetail_competence_code(competence.competence);
setdetail_competence_niveau(competence.niveau);
setselected_competence_id(competence._id);
setDialog_1_open_competence(true);
}}
className="detail_activite">
<nav className="detail_header" recid={competence.niveau}> {competence.competence} : {competence.note} </nav>
<nav recid={competence.niveau} >
<br />
{competence.niveau}<br />
{parseFloat(String(competence.note)) && <Rating
name="dialog_opport_prio"
id="dialog_opport_prio"
precision={0.5}
value={String(competence.note)}
/>}
</nav>
</nav>
</nav>
))}
</div>
<div className="div_row" style={{ "border": "None" }}>
<div className="div_row_gauche div_row_gauche_etendu" style={{ "textAlign": "left", "paddingLeft": "5px" }}>
<Button variant="outlined" onClick={(event) => {
setDialog_1_open_competence(true);
}}
className="detail_class_submenu bton_add_session"
id='menu_add_participant' name='menu_add_participant'>Ajout Compétence
<IoAddCircleOutline style={{ "fontSize": "x-large", "color": "green" }} />
</Button>
<br />
{New_Getall_Partner_Competence_List_result && <div>
New_Getall_Partner_Competence_List_result = {New_Getall_Partner_Competence_List_result}
</div>}
</div>
</div>
</div>}
</div >
);

View File

@ -58,6 +58,8 @@ const Partner_Configuration_Technique = (props) => {
const [selectionModel_crm_opportunite_etape, setselectionModel_crm_opportunite_etape] = React.useState([]);
const [selectionModel_competence, setselectionModel_competence] = React.useState([]);
const [rows_order_lines, setrows_order_lines] = useState([]);
const [selectionModel_order_lines, setselectionModel_order_lines] = React.useState([]);
@ -410,6 +412,75 @@ const Partner_Configuration_Technique = (props) => {
}
]
const columns_list_competence = [
{ field: '_id', headerName: '_id', hide: true },
{ field: 'id', headerName: 'id', hide: true },
{ field: 'description', headerName: 'Description', flex: 1, hide: false, editable: false },
{ field: 'domaine', headerName: 'Domaine', flex: 1, hide: false, editable: false },
{ field: 'metier', headerName: 'Métier', flex: 1, hide: false, editable: false },
{ field: 'commentaire', headerName: 'Commentaire', flex: 1, hide: false, editable: false },
{
field: "delete", headerName: 'Supprimer',
renderCell: (cellValues) => {
return (
<Popup
trigger={<Button
>
<CiTrash />
</Button>}
modal
nested
position="center center"
>
{close => (
<div>
<button className="gest_close" onClick={close}>
&times;
</button>
<div className="gest_header"> MySy Information </div>
<div className="gest_content">
{' '}
En confirmant cette opération, la compétence sera <i><font color="red"> définitivement supprimée</font></i>. <br />
</div>
<div className="gest_actions">
<div style={{ "width": "45%", "float": "left" }}>
<button className="gest_bton_popup" onClick={(event) => {
handleClick_delete_competence(event, cellValues);
//console.log('modal closed ');
close();
}}> Valider </button>
</div>
<div style={{ "width": "45%", "float": "right" }}>
<button
className="gest_bton_popup"
onClick={() => {
//console.log('modal closed ');
close();
}}
>
Annuler
</button>
</div>
</div>
</div>
)}
</Popup>
);
}
}
]
const myRef = useRef(null)
@ -421,6 +492,7 @@ const Partner_Configuration_Technique = (props) => {
Getall_Partner_Site_Formation();
Getall_Partner_Paiement_Condition();
Getall_Partner_CRM_Opportunite_Etape();
Getall_Partner_Competence_List();
if (document.getElementById('myRef_head')) {
var divh = document.getElementById('myRef_head').offsetTop;
@ -775,6 +847,85 @@ const Partner_Configuration_Technique = (props) => {
}
const [New_Getall_Partner_Competence_List_result, setNew_Getall_Partner_Competence_List_result] = useState([]);
const [Getall_Partner_Competence_List_api, setGetall_Partner_Competence_List_api] = useState();
const [Getall_Partner_Competence_List_message, setGetall_Partner_Competence_List_message] = useState();
const [Getall_Partner_Competence_List_result, setGetall_Partner_Competence_List_result] = useState([]);
function Getall_Partner_Competence_List(event) {
var form = new FormData();
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Get_Competence_no_filter/";
setLoading(true);
axios.post(myurl, form).then(res => {
setLoading(false);
if (String(res.data.status) === String("true")) {
//console.log(" In Getall_Partner_Competence_List res.data.status = " + res.data.status);
//console.log(" In Getall_Partner_Competence_List res.data.message r_class = " + res.data.message);
setGetall_Partner_Competence_List_api("true");
setGetall_Partner_Competence_List_result(res.data.message);
var new_data2 = [];
const new_data = res.data.message.map((x) => {
//---
var localid = JSON.parse(x).id;
var local_id = JSON.parse(x)._id;
var local_description = JSON.parse(x).description;
//---
var node = {
"_id": local_id,
"id": localid,
"label": local_description,
"description": local_description,
};
new_data2.push(node);
});
//---
var node = {
"_id": "",
"id": "",
"label": "",
"code": "",
"description": "",
"rang": "",
};
new_data2.push(node);
if (new_data2.length > 0)
setNew_Getall_Partner_Competence_List_result(new_data2);
}
else {
setGetall_Partner_Competence_List_api("false");
setGetall_Partner_Competence_List_message(res.data.message);
alert(res.data.message);
}
}).catch((error) => {
setLoading(false);
console.warn('Not good man :( Getall_Partner_Competence_List = ', error);
setGetall_Partner_Competence_List_api("false");
alert(" Impossible de recuperer la liste des compétences ");
//setmyApimyApiMessage("")
})
}
const [display_detail_config, setdisplay_detail_config] = React.useState();
const [selected_row_id_val, setselected_row_id_val] = React.useState();
@ -973,6 +1124,8 @@ const Partner_Configuration_Technique = (props) => {
const [gridline_crm_opport_id, setgridline_crm_opport_id] = useState("");
const [gridline_competence_id, setgridline_competence_id] = useState("");
const [display_detail_type_client, setdisplay_detail_type_client] = React.useState();
@ -1069,6 +1222,13 @@ const Partner_Configuration_Technique = (props) => {
const [p_detail_crm_opport_rang, setp_detail_crm_opport_rang] = useState("");
const [selected_competence_id, setselected_competence_id] = useState("");
const [p_detail_competence_description, setp_detail_competence_description] = useState("");
const [p_detail_competence_domaine, setp_detail_competence_domaine] = useState("");
const [p_detail_competence_metier, setp_detail_competence_metier] = useState("");
const [p_detail_competence_commentaire, setp_detail_competence_commentaire] = useState("");
const [Add_Update_Client_Type_api, setAdd_Update_Client_Type_api] = useState();
const [Add_Update_Client_Type_message, setAdd_Update_Client_Type_message] = useState();
@ -1479,6 +1639,54 @@ const Partner_Configuration_Technique = (props) => {
}
const [handleClick_delete_competence_api, sethandleClick_delete_competence_api] = useState();
const [handleClick_delete_competence_message, sethandleClick_delete_competence_message] = useState();
const [handleClick_delete_competence_result, sethandleClick_delete_competence_result] = useState();
function handleClick_delete_competence(event, cellValues) {
var local_competence_id = cellValues.row._id;
var form = new FormData();
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
form.append("competence_id", local_competence_id);
var myurl = process.env.REACT_APP_API_URL + "myclass/api/Delete_Given_Competence/";
setLoading(true);
axios.post(myurl, form).then(res => {
setLoading(false);
if (String(res.data.status) === String("true")) {
//console.log(" In handleClick_delete_competence res.data.status = " + res.data.status);
//console.log(" In handleClick_delete_competence res.data.message r_class = " + res.data.message);
sethandleClick_delete_competence_api("true");
sethandleClick_delete_competence_result(res.data.message);
Getall_Partner_Competence_List();
alert(res.data.message);
}
else {
sethandleClick_delete_competence_api("false");
sethandleClick_delete_competence_message(res.data.message);
alert(res.data.message);
}
}).catch((error) => {
setLoading(false);
console.warn('Not good man :( handleClick_delete_competence = ', error);
sethandleClick_delete_competence_api("false");
alert(" Impossible de supprimer la compétence");
//setmyApimyApiMessage("")
})
}
const New_Config_Point = [
{ "id": "tva", "label": "tva", "value": "tva" },
{ "id": "smtp_server", "label": "smtp_server", "value": "smtp_server" },
@ -1554,12 +1762,10 @@ const Partner_Configuration_Technique = (props) => {
const Dialog_crm_opport_1_handleClose_buton = () => {
setgridline_crm_opport_id("");
setselected_crm_opport_etape_id("");
setp_detail_crm_opport_code("");
setp_detail_crm_opport_description("");
setp_detail_crm_opport_rang("");
setDialog_crm_opport_1_open(false);
};
@ -1624,6 +1830,85 @@ const Partner_Configuration_Technique = (props) => {
})
}
const [Add_Update_Competence_api, setAdd_Update_Competence_api] = useState();
const [Add_Update_Competence_message, setAdd_Update_Competence_message] = useState();
const [Add_Update_Competence_result, setAdd_Update_Competence_result] = useState();
function Add_Update_Competence(event) {
var form = new FormData();
const stored_cookie = getCookie('tokenmysypart');
form.append("token", stored_cookie);
var myurl = "";
if (String(selected_competence_id).trim().length > 2) {
// Il s'agit d'une mise à jour
myurl = process.env.REACT_APP_API_URL + "myclass/api/Update_Competence/";
form.append("competence_id", selected_competence_id);
form.append("description", p_detail_competence_description);
form.append("domaine", p_detail_competence_domaine);
form.append("metier", p_detail_competence_metier);
form.append("commentaire", p_detail_competence_commentaire);
} else {
// Il s'agit d'une creation
myurl = process.env.REACT_APP_API_URL + "myclass/api/Add_Competence/";
form.append("description", p_detail_competence_description);
form.append("domaine", p_detail_competence_domaine);
form.append("metier", p_detail_competence_metier);
form.append("commentaire", p_detail_competence_commentaire);
}
setLoading(true);
axios.post(myurl, form).then(res => {
setLoading(false);
if (String(res.data.status) === String("true")) {
//console.log(" In Add_Update_Competence res.data.status = " + res.data.status);
//console.log(" In Add_Update_Competence res.data.message r_class = " + res.data.message);
setAdd_Update_Competence_api("true");
setAdd_Update_Competence_result(res.data.message);
Dialog_competence_1_handleClose_buton();
Getall_Partner_Competence_List();
alert(res.data.message);
}
else {
setAdd_Update_Competence_api("false");
setAdd_Update_Competence_message(res.data.message);
alert(res.data.message);
}
}).catch((error) => {
setLoading(false);
console.warn('Not good man :( Add_Update_Competence = ', error);
setAdd_Update_Competence_api("false");
alert(" Impossible d'ajouter / mettre à jour la compétence ");
//setmyApimyApiMessage("")
})
}
const [Dialog_competence_1_message, setDialog_competence_1_message] = React.useState(false);
const [Dialog_competence_1_open, setDialog_competence_1_open] = React.useState(false);
const Dialog_competence_1_handleClose = () => {
};
const Dialog_competence_1_handleClose_buton = () => {
setgridline_competence_id("");
setselected_competence_id("");
setp_detail_competence_description("");
setp_detail_competence_domaine("");
setp_detail_competence_metier("");
setp_detail_competence_commentaire("");
setDialog_competence_1_open(false);
};
return (
<div className="partner_configuration_technique">
@ -1631,6 +1916,118 @@ const Partner_Configuration_Technique = (props) => {
<div className="mysy_spinner"> <img src={img_loading_spin} /> </div>
</div>}
{/*** COMPETENCE */}
<Dialog
open={Dialog_competence_1_open}
onClose={Dialog_competence_1_handleClose}
className="displaypartnersession"
>
<DialogTitle> Compétence </DialogTitle>
<DialogContent className="DialogContent_width">
<div className="session_caract_Dialog" > Description
<TextField
sx={{ '& legend': { display: 'none' }, '& fieldset': { top: 0 }, }}
name="event_dialog_competence_desc"
id="event_dialog_competence_desc"
fullWidth
value={p_detail_competence_description}
onChange={(e) => {
setp_detail_competence_description(e.target.value);
}
}
/>
</div>
<div className="session_caract_Dialog" > Domaine
<TextField
sx={{ '& legend': { display: 'none' }, '& fieldset': { top: 0 }, }}
name="event_dialog_competence_domaine"
id="event_dialog_competence_domaine"
fullWidth
value={p_detail_competence_domaine}
onChange={(e) => {
setp_detail_competence_domaine(e.target.value);
}
}
/>
</div>
<div className="session_caract_Dialog" > Métier
<TextField
sx={{ '& legend': { display: 'none' }, '& fieldset': { top: 0 }, }}
name="event_dialog_competence_metier"
id="event_dialog_competence_metier"
fullWidth
inputProps={{ min: "0", max: "100", step: "1" }}
value={p_detail_competence_metier}
onChange={(e) => {
setp_detail_competence_metier(e.target.value);
}
}
/>
</div>
<div className="session_caract_Dialog" > commentaire
<TextField
sx={{ '& legend': { display: 'none' }, '& fieldset': { top: 0 }, }}
name="event_dialog_competence_comment"
id="event_dialog_competence_comment"
fullWidth
inputProps={{ min: "0", max: "100", step: "1" }}
value={p_detail_competence_commentaire}
onChange={(e) => {
setp_detail_competence_commentaire(e.target.value);
}
}
/>
</div>
</DialogContent>
<DialogActions>
<div className="div_row">
<div className="div_row_gauche">
{String(selected_competence_id).trim().length > 2 && <Button onClick={Add_Update_Competence} className="bton_enreg_dialog">Mettre à jour</Button>}
{String(selected_competence_id).trim() === "" && <Button onClick={Add_Update_Competence} className="bton_enreg_dialog">Ajouter</Button>}
</div>
<div className="div_row_droite" style={{ "textAlign": 'center' }}>
<Button onClick={Dialog_competence_1_handleClose_buton} className="bton_annule_dialog" >Fermer</Button>
</div>
</div>
</DialogActions>
</Dialog>
{/*** FIN COMPETENCE */}
<Dialog
open={Dialog_1_open}
onClose={Dialog_1_handleClose}
@ -3335,6 +3732,191 @@ const Partner_Configuration_Technique = (props) => {
</div>
</div>
<div>
<div className="div_row" style={{ paddingRight: '10px' }}>
<h3> Liste des compétences </h3>
<div className="session_data">
<div style={{ "border": "None" }}>
<div style={{ height: 550, width: '100%', paddingRight: '5px' }}>
&nbsp;
<Box
sx={{
height: 500,
width: '100%',
paddingRight: '1px',
// Gestion des cellule "statut"
'& .cell--status--encours': {
backgroundColor: '#E6F7C8',
color: '#1a3e72',
fontWeight: 'light',
},
'& .cell--status--traite': {
backgroundColor: '#E6CEAA',
color: '#F9E79F',
fontWeight: 'light',
},
/*"& .MuiDataGrid-virtualScrollerRenderZone": {
"& .MuiDataGrid-row": {
"&:nth-child(2n)": { backgroundColor: "rgba(235, 235, 235, .7)" }
}
},*/
"& .MuiDataGrid-columnHeaders": {
backgroundColor: "#c8cfd5",
color: "black",
fontSize: 14
},
'& .line--statut--selected': {
backgroundColor: '#FBF2EF',
color: 'black',
},
'& .line--statut--pair': {
backgroundColor: 'rgba(235, 235, 235, .7)',
color: 'black',
},
'& .line--statut--impair': {
backgroundColor: '#FFFFFF',
color: 'black',
},
}}
>
<DataGrid
checkboxSelection
onSelectionModelChange={(newSelectionModel) => {
setselectionModel_competence(newSelectionModel);
}}
selectionModel={selectionModel_competence}
localeText={frFR.components.MuiDataGrid.defaultProps.localeText}
rows={Getall_Partner_Competence_List_result.map((item, index) => (
{
id: index,
_id: JSON.parse(item)._id,
description: JSON.parse(item).description,
domaine: JSON.parse(item).domaine,
metier: JSON.parse(item).metier,
commentaire: JSON.parse(item).commentaire,
}
))}
columns={columns_list_competence}
pageSize={10}
className="datagridclass"
onRowDoubleClick={(newSelectionModel) => {
setgridline_competence_id(newSelectionModel.row.id);
setselected_competence_id(newSelectionModel.row._id);
setp_detail_competence_description(newSelectionModel.row.description);
setp_detail_competence_domaine(newSelectionModel.row.domaine);
setp_detail_competence_metier(newSelectionModel.row.metier);
setp_detail_competence_commentaire(newSelectionModel.row.commentaire);
setDialog_competence_1_open(true);
}}
rowsPerPageOptions={[10]}
//disableSelectionOnClick
components={{
Toolbar: GridToolbar,
}}
//sx={datagridSx}
getCellClassName={(params) => {
//field === "order_header_status"
if (params.field === "order_header_status" && String(params.value) == "0") {
return 'cell--status--brouillon';
}
if (params.field === "order_header_status" && String(params.value) == "1") {
return 'cell--status--encours';
}
if (params.field === "order_header_status" && String(params.value) == "2") {
return 'cell--status--traite';
}
if (params.field === "order_header_status" && String(params.value) == "3") {
return 'cell--status--facture';
}
}}
getRowClassName={(params) => {
if (String(params.row.status) === "-1") {
return 'line--statut--annule';
}
if (String(params.row.status) === "0") {
return 'line--statut--preinscrit';
}
if (String(params.row.status) === "1") {
return 'line--statut--inscrit';
}
// Pour la gestion de la couleur de zone double cliquée
if (String(params.row.id) === String(gridline_id)) {
return 'line--statut--selected';
}
else if (parseInt(String(params.row.id)) % 2 === 0) {
return 'line--statut--pair';
}
else if (parseInt(String(params.row.id)) % 2 !== 0) {
return 'line--statut--impair';
}
}}
/>
</Box>
<br />
</div>
</div>
</div>
<div className="div_row" style={{ "border": "None" }}>
<div className="div_row_gauche div_row_gauche_etendu" style={{ "textAlign": "left", "paddingLeft": "5px" }}>
<Button variant="outlined" onClick={() => {
setselected_competence_id("");
setp_detail_competence_description("");
setp_detail_competence_domaine("");
setp_detail_competence_metier("");
setp_detail_competence_commentaire("");
setDialog_competence_1_open(true);
}}
className="detail_class_submenu bton_add_session"
id='menu_import_participant' name='menu_import_participant'>Ajout 1 compétence
<IoAddCircleOutline style={{ "fontSize": "x-large", "color": "green" }} />
</Button>
</div>
</div>
<div className="div_row" ref={myRef_type_client} id="myRef_type_client"> &nbsp;</div>
</div>
</div>
</div>
)
}

View File

@ -598,6 +598,12 @@
float: left;
}
.block_competence {
width: 50%;
float: left;
margin-bottom: 1.5rem;
}
}
@media only screen and (min-width: 601px) and (max-width: 991px) {
@ -1187,6 +1193,12 @@
float: left;
}
.block_competence {
width: 50%;
float: left;
margin-bottom: 1.5rem;
}
}
@media only screen and (min-width: 992px) and (max-width: 1199px) {
@ -1675,6 +1687,13 @@
float: left;
}
.block_competence {
width: 50%;
float: left;
margin-bottom: 1.5rem;
}
}
@ -2234,6 +2253,34 @@
float: left;
}
.block_competence {
width: 30%;
float: left;
margin-bottom: 1rem;
}
.detail_activite {
display: inline-block;
color: black;
border: none;
background: white;
box-shadow: 1px 1px 10px 1px rgb(0 0 0 / 15%);
cursor: pointer;
vertical-align: middle;
padding: 5px;
text-align: left;
width: 20rem;
border-radius: 10px !important;
height: 7rem !important;
font-size: small;
padding-bottom: 10px;
}
.detail_activite:hover {
box-shadow: 5px 1px 5px 1px rgb(0 0 0 / 25%);
}
}
.session_caract_Dialog_comment_2_lines {

View File

@ -1095,7 +1095,7 @@
.block_activite {
width: 30%;
width: 30%;
float: left;
margin-bottom: 1rem;
}