5 changed files with 2469 additions and 111 deletions
@ -1,25 +0,0 @@ |
|||||||
import logo from './logo.svg'; |
|
||||||
import './App.css'; |
|
||||||
|
|
||||||
function App() { |
|
||||||
return ( |
|
||||||
<div className="App"> |
|
||||||
<header className="App-header"> |
|
||||||
<img src={logo} className="App-logo" alt="logo" /> |
|
||||||
<p> |
|
||||||
Edit <code>src/App.js</code> and save to reload. |
|
||||||
</p> |
|
||||||
<a |
|
||||||
className="App-link" |
|
||||||
href="https://reactjs.org" |
|
||||||
target="_blank" |
|
||||||
rel="noopener noreferrer" |
|
||||||
> |
|
||||||
Learn React |
|
||||||
</a> |
|
||||||
</header> |
|
||||||
</div> |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
export default App; |
|
||||||
@ -0,0 +1,48 @@ |
|||||||
|
import { useEffect, useRef, useState } from "react"; |
||||||
|
|
||||||
|
function useInterval(callback, delay) { |
||||||
|
const savedCallback = useRef(); |
||||||
|
|
||||||
|
// Remember the latest callback.
|
||||||
|
useEffect(() => { |
||||||
|
savedCallback.current = callback; |
||||||
|
}, [callback]); |
||||||
|
|
||||||
|
// Set up the interval.
|
||||||
|
useEffect(() => { |
||||||
|
function tick() { |
||||||
|
savedCallback.current(); |
||||||
|
} |
||||||
|
if (delay !== null) { |
||||||
|
let id = setInterval(tick, delay); |
||||||
|
return () => clearInterval(id); |
||||||
|
} |
||||||
|
}, [delay]); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function Countdown({ duration, onComplete }) { |
||||||
|
// Initialize the countdown timer with the duration prop
|
||||||
|
const [timeLeft, setTimeLeft] = useState(duration); |
||||||
|
|
||||||
|
// Decrement the timer by 1 second every 1000ms
|
||||||
|
useInterval(() => { |
||||||
|
if(timeLeft === 1) { |
||||||
|
onComplete() |
||||||
|
} else{ |
||||||
|
|
||||||
|
setTimeLeft(timeLeft - 1); |
||||||
|
} |
||||||
|
}, 1000); |
||||||
|
|
||||||
|
// Return the time left formatted as minutes and seconds
|
||||||
|
let minutes = Math.floor(timeLeft / 60); |
||||||
|
let seconds = timeLeft % 60; |
||||||
|
return ( |
||||||
|
<div>{seconds} |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export default Countdown |
||||||
@ -1,17 +1,226 @@ |
|||||||
import React from 'react'; |
import React, { useEffect, useState } from "react"; |
||||||
import ReactDOM from 'react-dom/client'; |
import ReactDOM from "react-dom/client"; |
||||||
import './index.css'; |
import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom"; |
||||||
import App from './App'; |
import firebase from "firebase/app"; |
||||||
import reportWebVitals from './reportWebVitals'; |
import "firebase/database"; |
||||||
|
import TextField from "@mui/material/TextField"; |
||||||
const root = ReactDOM.createRoot(document.getElementById('root')); |
import { Stack } from "@mui/system"; |
||||||
root.render( |
import { Button } from "@mui/material"; |
||||||
<React.StrictMode> |
import { useForm } from "react-hook-form"; |
||||||
<App /> |
import Countdown from "./Countdown"; |
||||||
</React.StrictMode> |
|
||||||
); |
import List from "@mui/material/List"; |
||||||
|
import ListItem from "@mui/material/ListItem"; |
||||||
|
import ListItemButton from "@mui/material/ListItemButton"; |
||||||
|
import ListItemText from "@mui/material/ListItemText"; |
||||||
|
import Checkbox from "@mui/material/Checkbox"; |
||||||
|
|
||||||
|
const MyForm = () => { |
||||||
|
const [mandato, cambiaMandato] = useState(false); |
||||||
|
const { register, handleSubmit } = useForm(); |
||||||
|
const onSubmit = ({ testo, autore }) => { |
||||||
|
var postListRef = firebase.database().ref("messaggi"); |
||||||
|
var newPostRef = postListRef.push(); |
||||||
|
console.log(newPostRef.key); |
||||||
|
newPostRef.set({ |
||||||
|
id: newPostRef.key, |
||||||
|
autore, |
||||||
|
testo, |
||||||
|
timestamp: firebase.database.ServerValue.TIMESTAMP, |
||||||
|
approvato: true, |
||||||
|
}); |
||||||
|
cambiaMandato(true); |
||||||
|
}; |
||||||
|
|
||||||
|
if (mandato) { |
||||||
|
return ( |
||||||
|
<Stack> |
||||||
|
<div>mandato e mo aspetti</div> |
||||||
|
<Countdown onComplete={() => cambiaMandato(false)} duration={5} /> |
||||||
|
</Stack> |
||||||
|
); |
||||||
|
} |
||||||
|
return ( |
||||||
|
<form onSubmit={handleSubmit(onSubmit)}> |
||||||
|
<Stack spacing={2}> |
||||||
|
<TextField |
||||||
|
{...register("testo", { required: true, maxLength: 20 })} |
||||||
|
id="outlined-basic" |
||||||
|
label="messaggio" |
||||||
|
variant="outlined" |
||||||
|
/> |
||||||
|
<TextField |
||||||
|
{...register("autore", { pattern: /^[A-Za-z]+$/i })} |
||||||
|
id="outlined-basic" |
||||||
|
label="da" |
||||||
|
variant="outlined" |
||||||
|
/> |
||||||
|
<Button type="submit" variant="contained"> |
||||||
|
manda |
||||||
|
</Button> |
||||||
|
</Stack> |
||||||
|
</form> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
const firebaseConfig = { |
||||||
|
apiKey: "AIzaSyASAEVOTQ38EmRoelz9qGiF6QsqpBOuU_k", |
||||||
|
authDomain: "messaggi-letsswing.firebaseapp.com", |
||||||
|
databaseURL: |
||||||
|
"https://messaggi-letsswing-default-rtdb.europe-west1.firebasedatabase.app", |
||||||
|
projectId: "messaggi-letsswing", |
||||||
|
storageBucket: "messaggi-letsswing.appspot.com", |
||||||
|
messagingSenderId: "154307951524", |
||||||
|
appId: "1:154307951524:web:f320027fb89982a3f05f31", |
||||||
|
}; |
||||||
|
|
||||||
|
firebase.initializeApp(firebaseConfig); |
||||||
|
|
||||||
|
function CheckboxListSecondary({ messaggi, onChecked }) { |
||||||
|
return ( |
||||||
|
<List |
||||||
|
dense |
||||||
|
sx={{ width: "100%", maxWidth: 360, bgcolor: "background.paper" }} |
||||||
|
> |
||||||
|
{messaggi.map((m) => { |
||||||
|
const labelId = `checkbox-list-secondary-label-${m.timestamp}`; |
||||||
|
return ( |
||||||
|
<ListItem |
||||||
|
key={m.timestamp} |
||||||
|
secondaryAction={ |
||||||
|
<Checkbox |
||||||
|
edge="end" |
||||||
|
onChange={() => onChecked(m)} |
||||||
|
checked={m.approvato} |
||||||
|
inputProps={{ "aria-labelledby": labelId }} |
||||||
|
/> |
||||||
|
} |
||||||
|
disablePadding |
||||||
|
> |
||||||
|
<ListItemButton> |
||||||
|
<ListItemText |
||||||
|
id={labelId} |
||||||
|
primary={`"${m.testo}" da ${m.autore}`} |
||||||
|
/> |
||||||
|
</ListItemButton> |
||||||
|
</ListItem> |
||||||
|
); |
||||||
|
})} |
||||||
|
</List> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
const Admin = () => { |
||||||
|
const [messaggi, cambiaMessaggi] = useState([]); |
||||||
|
const [indiceCorrente, cambiaindiceCorrente] = useState(0); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
// Get a reference to the messages node in the Realtime Database
|
||||||
|
var messagesRef = firebase.database().ref("/messaggi"); |
||||||
|
|
||||||
|
messagesRef.on("value", function (snapshot) { |
||||||
|
var messaggi = snapshot.val(); |
||||||
|
messaggi = Object.keys(messaggi).map((d) => messaggi[d]); |
||||||
|
cambiaMessaggi(messaggi); |
||||||
|
}); |
||||||
|
|
||||||
|
messagesRef.on("child_changed", function (snapshot) { |
||||||
|
var messaggio = snapshot.val(); |
||||||
|
const i = messaggi.findIndex((m) => messaggio.timestamp === m.timestamp); |
||||||
|
}); |
||||||
|
}, []); |
||||||
|
|
||||||
|
if (!messaggi.length) return <div>nessun messaggio</div>; |
||||||
|
|
||||||
|
return ( |
||||||
|
<Stack> |
||||||
|
<hr /> |
||||||
|
<CheckboxListSecondary |
||||||
|
messaggi={messaggi} |
||||||
|
onChecked={(m) => { |
||||||
|
firebase |
||||||
|
.database() |
||||||
|
.ref("messaggi/" + m.id) |
||||||
|
.update({ |
||||||
|
approvato: !m.approvato, |
||||||
|
}); |
||||||
|
}} |
||||||
|
/> |
||||||
|
</Stack> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
// If you want to start measuring performance in your app, pass a function
|
const Proiezione = () => { |
||||||
// to log results (for example: reportWebVitals(console.log))
|
const [messaggi, cambiaMessaggi] = useState([]); |
||||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
const [indiceCorrente, cambiaindiceCorrente] = useState(0); |
||||||
reportWebVitals(); |
|
||||||
|
useEffect(() => { |
||||||
|
// Get a reference to the messages node in the Realtime Database
|
||||||
|
var messagesRef = firebase.database().ref("/messaggi"); |
||||||
|
|
||||||
|
messagesRef.on("child_added", function (snapshot) { |
||||||
|
var messaggio = snapshot.val(); |
||||||
|
cambiaMessaggi((oldArray) => |
||||||
|
[...oldArray, messaggio].sort((a, b) => b.timestamp - a.timestamp) |
||||||
|
); |
||||||
|
}); |
||||||
|
|
||||||
|
messagesRef.on("child_changed", function (snapshot) { |
||||||
|
var messaggio = snapshot.val(); |
||||||
|
|
||||||
|
cambiaMessaggi((oldArray) => { |
||||||
|
var nuoviMessaggi = [...oldArray]; |
||||||
|
var nuovoIndice = oldArray.findIndex((d) => d.id === messaggio.id); |
||||||
|
if (nuovoIndice != -1) { |
||||||
|
nuoviMessaggi[nuovoIndice] = messaggio; |
||||||
|
} |
||||||
|
return nuoviMessaggi; |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, []); |
||||||
|
|
||||||
|
const nextMessage = (i) => { |
||||||
|
if(i === indiceCorrente) return |
||||||
|
let nuovoIndice = (i + 1) % messaggi.length; |
||||||
|
|
||||||
|
if (!messaggi[nuovoIndice].approvato) { |
||||||
|
nextMessage(nuovoIndice); |
||||||
|
} else { |
||||||
|
cambiaindiceCorrente(nuovoIndice) |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const messaggioCorrente = messaggi[indiceCorrente]; |
||||||
|
|
||||||
|
return ( |
||||||
|
<div> |
||||||
|
<MyForm /> |
||||||
|
{!messaggi.filter((m) => m.approvato).length && ( |
||||||
|
<div>nessun messaggio</div> |
||||||
|
)} |
||||||
|
{messaggi.filter((m) => m.approvato).length && ( |
||||||
|
<div> |
||||||
|
<h1>{messaggioCorrente.testo}</h1> |
||||||
|
<p>da {messaggioCorrente.autore}</p> |
||||||
|
</div> |
||||||
|
)} |
||||||
|
<Button onClick={()=>nextMessage(indiceCorrente)}>next</Button> |
||||||
|
|
||||||
|
<Admin /> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
const Input = () => { |
||||||
|
return <div> Input </div>; |
||||||
|
}; |
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById("root")).render( |
||||||
|
<Router> |
||||||
|
<Routes> |
||||||
|
<Route path="/" element={<Input />} /> |
||||||
|
<Route path="proiezione" element={<Proiezione />} /> |
||||||
|
<Route path="admin" element={<Admin />} /> |
||||||
|
</Routes> |
||||||
|
</Router> |
||||||
|
); |
||||||
|
|||||||
Loading…
Reference in new issue