Encara no funciona la comprovació de rols a la barra. Tampoc està factoritzat l'estat de logueig.
This commit is contained in:
parent
04d436a10f
commit
2b4cccb598
@ -7,6 +7,9 @@ import { useSubscribe, useTracker, useFind } from 'meteor/react-meteor-data/susp
|
||||
import { Pobles } from './Pobles';
|
||||
import { Necessitats } from './Necessitats';
|
||||
import { Tipus } from './Tipus';
|
||||
import { BarraNav } from './BarraNav/BarraNav';
|
||||
|
||||
import { UserStat } from './BarraNav/UserStat';
|
||||
|
||||
const Loguejat = lazy(async () => await import('/imports/ui/Loguejat.jsx'));
|
||||
|
||||
@ -17,6 +20,10 @@ export const App = () => {
|
||||
// const userId = await Meteor.userAsync();
|
||||
|
||||
return <BrowserRouter>
|
||||
<UserStat />
|
||||
|
||||
<BarraNav />
|
||||
|
||||
<Routes>
|
||||
<Route path="/" element={ <Suspense fallback={<>Carregant...</>}>{user ? <Loguejat /> : <Login/>}</Suspense> } />
|
||||
<Route path="/pobles" element={ <Pobles /> } />
|
||||
|
||||
70
imports/ui/BarraNav/BarraNav.jsx
Normal file
70
imports/ui/BarraNav/BarraNav.jsx
Normal file
@ -0,0 +1,70 @@
|
||||
import React, {useState, useEffect} from "react";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Roles } from 'meteor/roles';
|
||||
|
||||
const BotóSecció = ({titol, linkto}) => {
|
||||
return <div style={{
|
||||
border: `1px solid #aaaa`,
|
||||
borderRadius: `.3rem`,
|
||||
padding: `.2rem`,
|
||||
backgroundColor: `lightblue`,
|
||||
margin: `.5rem`
|
||||
}}>
|
||||
<Link to={linkto} >{titol}</Link>
|
||||
</div>;
|
||||
};
|
||||
|
||||
const SeccióPobles = () => <BotóSecció
|
||||
titol="Pobles"
|
||||
linkto="/pobles"
|
||||
/>;
|
||||
|
||||
const SeccióNecessitats = () => <BotóSecció
|
||||
titol="Necessitats"
|
||||
linkto="/necessitats"
|
||||
/>;
|
||||
|
||||
const SeccióTipus = () => <BotóSecció
|
||||
titol="Tipus"
|
||||
linkto="/tipus"
|
||||
/>;
|
||||
|
||||
const SeccióUsuaris = () => <BotóSecció
|
||||
titol="Usuaris"
|
||||
linkto="/usuaris"
|
||||
/>;
|
||||
|
||||
const PanellSeccions = ({children}) => {
|
||||
return <><div style={{
|
||||
display: `flex`,
|
||||
border: `1px solid #cccc`,
|
||||
padding: `.5rem`,
|
||||
borderRadius: `.5rem`,
|
||||
backgroundColor: `lightslategray`
|
||||
}}>{children}</div>
|
||||
<br />
|
||||
</>;
|
||||
};
|
||||
|
||||
const BarraNav = () => {
|
||||
const [esAdministrador, setEsAdministrador] = useState(false);
|
||||
const userId = Meteor.userId();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const comprovaAdmin = await Roles.userIsInRoleAsync(userId, ["admin"]);
|
||||
setEsAdministrador(comprovaAdmin);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
|
||||
return <PanellSeccions >
|
||||
{ esAdministrador && <SeccióUsuaris />}
|
||||
<SeccióPobles />
|
||||
<SeccióNecessitats />
|
||||
<SeccióTipus />
|
||||
</PanellSeccions>;
|
||||
};
|
||||
|
||||
export { BarraNav };
|
||||
191
imports/ui/BarraNav/UserStat.jsx
Normal file
191
imports/ui/BarraNav/UserStat.jsx
Normal file
@ -0,0 +1,191 @@
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import { useTracker } from 'meteor/react-meteor-data/suspense';
|
||||
|
||||
// import { FilesCol } from '/imports/api/files.js';
|
||||
import { useNavigate, Link } from 'react-router-dom';
|
||||
|
||||
import { Roles } from 'meteor/roles';
|
||||
// import { useUserContext } from '/imports/api/contexts/AppContext';
|
||||
// import { groupBy } from 'lodash';
|
||||
|
||||
//import Radium from 'radium';
|
||||
|
||||
|
||||
const IndicadorMissatges = ({notif}) => {
|
||||
return <span style={{
|
||||
position: `relative`
|
||||
}}>
|
||||
{notif && <span className='fas fa-solid fa-envelope' />}
|
||||
<span style={{
|
||||
borderRadius: `50%`,
|
||||
background: notif ? `red` : ``,
|
||||
position: `absolute`,
|
||||
width: `.4em`,
|
||||
aspectRatio: `1 / 1`
|
||||
}}/>
|
||||
</span>;
|
||||
};
|
||||
|
||||
const UserStat = ({setEditaPerfil}) => {
|
||||
|
||||
const [esAdministrador, setEsAdministrador] = useState(false);
|
||||
|
||||
const u = useTracker("user", async () => await Meteor.userAsync());
|
||||
const userId = Meteor.userId();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const comprovaAdmin = await Roles.userIsInRoleAsync(userId, ["admin"]);
|
||||
setEsAdministrador(comprovaAdmin);
|
||||
})();
|
||||
}, []);
|
||||
|
||||
// const u = useUserContext();
|
||||
|
||||
|
||||
// console.log("UUU: ", u);
|
||||
|
||||
const navigate = useNavigate();
|
||||
// const files = useTracker(() => {
|
||||
// const filesHandle = Meteor.subscribe('files.avatar');
|
||||
// // const docsReadyYet = filesHandle.ready();
|
||||
// const files = FilesCol?.find({"meta.userId": Meteor.userId()}, {sort: {name: 1}}).fetch(); // Meteor.userId() ?? "nop"
|
||||
|
||||
// return files;
|
||||
// });
|
||||
|
||||
// const uname = useTracker(() => Meteor.user({ fields: { 'username': 1 } })?.username );
|
||||
|
||||
const [mostraMenu, setMostraMenu] = useState(false);
|
||||
|
||||
//const avatarLink = u.avatarLink;
|
||||
|
||||
// alert("avLnk: ", u.profile.avatarLink);
|
||||
|
||||
return <>
|
||||
<div
|
||||
style={{
|
||||
// color: `lightblue`,
|
||||
|
||||
top: `1em`,
|
||||
// right: `1em`,
|
||||
left: `1em`,
|
||||
cursor: `pointer`,
|
||||
background: `yellow`,
|
||||
border: `lightblue 3px solid`,
|
||||
//padding: `.15em`,
|
||||
borderRadius: `.7em`,
|
||||
fontWeight: `bold`,
|
||||
display: `inline-block`
|
||||
}}
|
||||
onMouseEnter={ev => {
|
||||
setMostraMenu(true);
|
||||
}}
|
||||
|
||||
// title="Logout"
|
||||
|
||||
onClick={ev => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
// console.log("u: ", u);
|
||||
|
||||
navigate(`/${u.username}`);
|
||||
|
||||
}}
|
||||
>
|
||||
{ esAdministrador && <div style={{
|
||||
color: `red`,
|
||||
fontSize: `xx-small`,
|
||||
// textAlign: `right`
|
||||
}}>ADMIN</div> }
|
||||
<img
|
||||
style={{
|
||||
width: `3em`,
|
||||
height: `3em`,
|
||||
borderRadius: `50%`,
|
||||
overflow: `hidden`,
|
||||
verticalAlign: `middle`,
|
||||
margin: `.3em`,
|
||||
border: `solid 4px whitesmoke`
|
||||
}}
|
||||
src={u?.profile?.avatarLink}
|
||||
/>
|
||||
|
||||
<span style={{
|
||||
verticalAlign: `middle`,
|
||||
margin: `0.3em 0.3em 0.3em auto`
|
||||
}}>{u?.username}</span>
|
||||
|
||||
|
||||
|
||||
<span
|
||||
style={{
|
||||
verticalAlign: `middle`,
|
||||
margin: `0.3em 0.3em 0.3em auto`,
|
||||
padding: `.2em`,
|
||||
// border: `2px solid grey`,
|
||||
color: `grey`,
|
||||
// borderRadius: `.3em`
|
||||
}}
|
||||
onClick={ev => {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
alert("Click en missatges");
|
||||
}}
|
||||
>
|
||||
<IndicadorMissatges notif={false} />
|
||||
</span>
|
||||
</div>
|
||||
{
|
||||
mostraMenu &&
|
||||
<div style={{
|
||||
position: `absolute`,
|
||||
background: `white`,
|
||||
// right: `0`,
|
||||
left: 0,
|
||||
top: `5em`,
|
||||
padding: `.4em .5em`,
|
||||
border: `1px #aaa`,
|
||||
cursor: `pointer`,
|
||||
zIndex: `200`
|
||||
}}
|
||||
onMouseLeave={ev => {
|
||||
setMostraMenu(false);
|
||||
}}
|
||||
>
|
||||
{/* <Link to="/c/config"> */}
|
||||
<div className="menuOp" style={{
|
||||
padding: `.2em`
|
||||
}}
|
||||
onClick={ev => {
|
||||
//setEditaPerfil(true);
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
navigate(`/c/config`);
|
||||
|
||||
}}
|
||||
>Configuración</div>
|
||||
{/* </Link> */}
|
||||
|
||||
<div className="menuOp" style={{
|
||||
padding: `.2em`
|
||||
}}
|
||||
onClick={() => {
|
||||
Meteor.logout(err => {
|
||||
err && alert(`Problema: ${err}`);
|
||||
});
|
||||
navigate(`/`);
|
||||
}}
|
||||
>Cierra la sesión</div>
|
||||
</div>
|
||||
}
|
||||
<br /><br />
|
||||
</>;
|
||||
};
|
||||
|
||||
export { UserStat };
|
||||
@ -2,47 +2,10 @@ import React from "react";
|
||||
import { useUserId } from 'meteor/react-meteor-accounts';
|
||||
import { Link } from 'react-router-dom';
|
||||
// import { styled } from 'styled-components'
|
||||
// import { BarraNav } from "./BarraNav/BarraNav";
|
||||
|
||||
// if (loguejat)
|
||||
|
||||
|
||||
const BotóSecció = ({titol, linkto}) => {
|
||||
return <div style={{
|
||||
border: `1px solid #aaaa`,
|
||||
borderRadius: `.3rem`,
|
||||
padding: `.2rem`,
|
||||
backgroundColor: `lightblue`,
|
||||
margin: `.5rem`
|
||||
}}>
|
||||
<Link to={linkto} >{titol}</Link>
|
||||
</div>;
|
||||
};
|
||||
|
||||
const SeccióPobles = () => <BotóSecció
|
||||
titol="Pobles"
|
||||
linkto="/pobles"
|
||||
/>;
|
||||
|
||||
const SeccióNecessitats = () => <BotóSecció
|
||||
titol="Necessitats"
|
||||
linkto="/necessitats"
|
||||
/>;
|
||||
|
||||
const SeccióTipus = () => <BotóSecció
|
||||
titol="Tipus"
|
||||
linkto="/tipus"
|
||||
/>;
|
||||
|
||||
const PanellSeccions = ({children}) => {
|
||||
return <div style={{
|
||||
display: `flex`,
|
||||
border: `1px solid #cccc`,
|
||||
padding: `.5rem`,
|
||||
borderRadius: `.5rem`,
|
||||
backgroundColor: `lightslategray`
|
||||
}}>{children}</div>;
|
||||
};
|
||||
|
||||
const Loguejat = () => {
|
||||
|
||||
const userId = useUserId();
|
||||
@ -52,12 +15,7 @@ const Loguejat = () => {
|
||||
|
||||
<br /><br />
|
||||
|
||||
<PanellSeccions >
|
||||
<SeccióPobles />
|
||||
<SeccióNecessitats />
|
||||
<SeccióTipus />
|
||||
</PanellSeccions>
|
||||
|
||||
{/* <BarraNav /> */}
|
||||
|
||||
<p>- poble (que cada poble només tinga accés a lo del seu poble, la resta de pobles no els han de poder tocar): Alaquàs / Albal / Aldaia / Alfafar / Algemesí / Alginet / Alcàsser / Benetússer / Beniparrell / Carlet / Catarroja / Dosaigües / Godelleta / Guadassuar / Iàtova / L'Alcúdia / Llocnou de la Corona / Massanassa / Paiporta / Parke Alkosa / Picanya / Sedaví / Setaigües / Utiel / València-Castellar Oliveral / València-Forn d'Alcedo / València-La Torre / Xest / Xiva / Llombai / Tremolar </p>
|
||||
<p>- estat: impossible de trobar / disponible / pendent / enviada / ha arribat (que cada poble puga tocar aquestes opcions dels subministres per al seu poble)</p>
|
||||
|
||||
@ -10,6 +10,7 @@ import { Roles } from 'meteor/roles';
|
||||
|
||||
import CreatableSelect from 'react-select/creatable';
|
||||
import AsyncCreatableSelect from 'react-select/async-creatable';
|
||||
import { BarraNav } from "./BarraNav/BarraNav";
|
||||
|
||||
|
||||
|
||||
@ -50,10 +51,8 @@ export const Necessitats = () => {
|
||||
borderRadius: `.3em`,
|
||||
backgroundColor: `lightcyan`
|
||||
}}>
|
||||
{ esEditor && <div style={{
|
||||
color: `red`
|
||||
}}>ADMINISTRADOR</div> }
|
||||
{necessitatSeleccionada && <h1>{necessitatSeleccionada._id}</h1>}
|
||||
|
||||
{necessitatSeleccionada && <h2>{necessitatSeleccionada._id}</h2>}
|
||||
<h1>Necessitats</h1>
|
||||
|
||||
<form
|
||||
|
||||
@ -5,6 +5,7 @@ import { useSubscribe, useTracker, useFind } from 'meteor/react-meteor-data/susp
|
||||
|
||||
import { Roles } from 'meteor/roles';
|
||||
// import { useUserId } from 'meteor/react-meteor-accounts';
|
||||
import { BarraNav } from "./BarraNav/BarraNav";
|
||||
|
||||
|
||||
|
||||
@ -38,27 +39,25 @@ export const Pobles = () => {
|
||||
borderRadius: `.3em`,
|
||||
backgroundColor: `lightcyan`
|
||||
}}>
|
||||
{ esEditor && <div style={{
|
||||
color: `red`
|
||||
}}>ADMINISTRADOR</div> }
|
||||
{pobleSeleccionat && <h1>{pobleSeleccionat._id}</h1>}
|
||||
|
||||
{pobleSeleccionat && <h2>{pobleSeleccionat._id}</h2>}
|
||||
<h1>Pobles</h1>
|
||||
|
||||
<form
|
||||
action={d => {
|
||||
try {
|
||||
Meteor.callAsync('editaOAfigPoble',
|
||||
{
|
||||
...pobleSeleccionat || [],
|
||||
nomPoble: d.get('nomPoble'),
|
||||
cp: d.get('cp') || "",
|
||||
comarca: d.get('comarca') || "",
|
||||
}).then(() => setPobleSeleccionat(null))
|
||||
.catch(err => console.error(err));
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
console.error(err);
|
||||
}
|
||||
try {
|
||||
Meteor.callAsync('editaOAfigPoble',
|
||||
{
|
||||
...pobleSeleccionat || [],
|
||||
nomPoble: d.get('nomPoble'),
|
||||
cp: d.get('cp') || "",
|
||||
comarca: d.get('comarca') || "",
|
||||
}).then(() => setPobleSeleccionat(null))
|
||||
.catch(err => console.error(err));
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
console.error(err);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="nomPoble">Població: </label><input name="nomPoble" type="text" defaultValue={ pobleSeleccionat ? pobleSeleccionat.nomPoble : ""}/><br />
|
||||
|
||||
@ -10,6 +10,7 @@ import Select from 'react-select';
|
||||
|
||||
import CreatableSelect from 'react-select/creatable';
|
||||
import AsyncCreatableSelect from 'react-select/async-creatable';
|
||||
import { BarraNav } from "./BarraNav/BarraNav";
|
||||
|
||||
|
||||
|
||||
@ -40,10 +41,17 @@ export const Tipus = () => {
|
||||
useSubscribe('tipus');
|
||||
const tipus = useTracker("tipus", () => TipusCollection.find().fetchAsync());
|
||||
|
||||
console.log("tipus: ", tipus);
|
||||
console.log("necessitats: ", necessitats);
|
||||
// console.log("tipus: ", tipus);
|
||||
// console.log("necessitats: ", necessitats);
|
||||
|
||||
console.log("tipusSeleccionat: ", tipusSeleccionat);
|
||||
// console.log("tipusSeleccionat: ", tipusSeleccionat);
|
||||
|
||||
|
||||
const filterTipus = (inputValue) => {
|
||||
return tipus.filter((i) =>
|
||||
i.titol.toLowerCase().includes(inputValue.toLowerCase())
|
||||
);
|
||||
};
|
||||
|
||||
const QuadreInfo_Tipus = () => {
|
||||
|
||||
@ -54,9 +62,7 @@ export const Tipus = () => {
|
||||
borderRadius: `.3em`,
|
||||
backgroundColor: `lightcyan`
|
||||
}}>
|
||||
{ esEditor && <div style={{
|
||||
color: `red`
|
||||
}}>ADMINISTRADOR</div> }
|
||||
|
||||
{tipusSeleccionat && <h1>{tipusSeleccionat._id}</h1>}
|
||||
<h1>Tipus</h1>
|
||||
|
||||
@ -87,11 +93,13 @@ export const Tipus = () => {
|
||||
si no
|
||||
tansols podrà assignar a un tipus predefinit o al de ALTRES
|
||||
*/}
|
||||
|
||||
<AsyncCreatableSelect
|
||||
name="selTipus"
|
||||
formatCreateLabel={(inputValue) => "Crear nou tipus..."}
|
||||
defaultOptions={tipus.map((v,i) => ({value: v._id, label: v.titol})).sort((a,b) => a.label.toLowerCase() > b.label.toLowerCase()) }
|
||||
onCreateOption={(inputValue) => Meteor.callAsync('afigTipus', {titol: inputValue})}
|
||||
isSearchable
|
||||
// loadOptions={tipus.map((v,i) => ({value: v, label: v.titol}))}
|
||||
/>
|
||||
|
||||
@ -159,10 +167,27 @@ export const Tipus = () => {
|
||||
{/* <SelectSearch options={options} value="sv" name="language" placeholder="Choose your language" /> */}
|
||||
|
||||
|
||||
{/* <ul>{
|
||||
<ul style={{
|
||||
display: `flex`,
|
||||
flexWrap: `wrap`,
|
||||
justifyContent: `space-evenly`,
|
||||
rowGap: `.3em`,
|
||||
alignContent: `space-around`
|
||||
}}>{
|
||||
tipus
|
||||
.sort((a,b) => a.nomPoble?.toLowerCase() > b.nomPoble?.toLowerCase())
|
||||
.map(pob => <li key={`pob_${pob._id}`}>{pob.nomPoble}{esEditor && <button onClick={() => {setPobleSeleccionat(pob)}}>Edita</button>}</li>)
|
||||
}</ul> */}
|
||||
.sort((a,b) => a.titol?.toLowerCase() > b.titol?.toLowerCase())
|
||||
.map(titol => <li
|
||||
key={`titol_${titol._id}`}
|
||||
style={{
|
||||
display: `block`,
|
||||
border: `1px solid #6666`,
|
||||
borderRadius: `.4em`,
|
||||
padding: `4px`,
|
||||
listStyle: `none`,
|
||||
backgroundColor: `${'lightgreen' || 'lightcoral'}`
|
||||
}}
|
||||
>
|
||||
{titol.titol}{esEditor && <button onClick={() => {setTipusSeleccionat(titol)}}>Edita</button>}</li>)
|
||||
}</ul>
|
||||
</Suspense>;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user