Add possibility to send picture through the app for certains questions
This commit is contained in:
parent
cbd500e13b
commit
28e1a0c4f8
5 changed files with 171 additions and 89 deletions
|
@ -3,8 +3,10 @@ import { useState, useEffect, useRef } from 'react'
|
||||||
import { io } from "socket.io-client"
|
import { io } from "socket.io-client"
|
||||||
import { getRandomQuestion } from "./questions"
|
import { getRandomQuestion } from "./questions"
|
||||||
import { useForceUpdate } from "./forceUpdate"
|
import { useForceUpdate } from "./forceUpdate"
|
||||||
import { IconCrown } from "@tabler/icons-react"
|
import { IconCrown, IconPhotoUp, IconCamera } from "@tabler/icons-react"
|
||||||
import { defaultAvatarImage } from '../avatarImage'
|
import { defaultAvatarImage } from '../avatarImage'
|
||||||
|
import { resizeBase64Image, getBase64OfImage } from '../utils'
|
||||||
|
import Webcam from 'react-webcam'
|
||||||
|
|
||||||
interface roomProps {
|
interface roomProps {
|
||||||
params: {
|
params: {
|
||||||
|
@ -23,7 +25,8 @@ export default function Home({ params }: roomProps) {
|
||||||
|
|
||||||
const [gameStarted, setGameStarted] = useState(false)
|
const [gameStarted, setGameStarted] = useState(false)
|
||||||
const [gameEnded, setGameEnded] = useState(false)
|
const [gameEnded, setGameEnded] = useState(false)
|
||||||
const [questionDisplayed, setQuestionDisplayed] = useState("")
|
const [questionReply, setQuestionReply] = useState({})
|
||||||
|
const [questionDisplayed, setQuestionDisplayed] = useState({})
|
||||||
const [possibleChoice, setPossibleChoice] = useState([])
|
const [possibleChoice, setPossibleChoice] = useState([])
|
||||||
const [totalVotes, setTotalVotes] = useState(0)
|
const [totalVotes, setTotalVotes] = useState(0)
|
||||||
const [choice, setChoice] = useState("")
|
const [choice, setChoice] = useState("")
|
||||||
|
@ -33,6 +36,9 @@ export default function Home({ params }: roomProps) {
|
||||||
const [questionAlreadyDone, setQuestionAlreadyDone] = useState([])
|
const [questionAlreadyDone, setQuestionAlreadyDone] = useState([])
|
||||||
|
|
||||||
const socketRef = useRef()
|
const socketRef = useRef()
|
||||||
|
const inputPhotoRef = useRef()
|
||||||
|
const photoModalRef = useRef()
|
||||||
|
const webcamRef = useRef()
|
||||||
const duration = 15
|
const duration = 15
|
||||||
const questionLimit = 10
|
const questionLimit = 10
|
||||||
|
|
||||||
|
@ -76,6 +82,11 @@ export default function Home({ params }: roomProps) {
|
||||||
setTotalVotes(0)
|
setTotalVotes(0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
socketRef.current.on("question_reply", (params) => {
|
||||||
|
console.log(params)
|
||||||
|
setQuestionReply(params)
|
||||||
|
})
|
||||||
|
|
||||||
socketRef.current.on("reset_game", (params) => {
|
socketRef.current.on("reset_game", (params) => {
|
||||||
setGameStarted(false)
|
setGameStarted(false)
|
||||||
setCountdown(0)
|
setCountdown(0)
|
||||||
|
@ -187,8 +198,36 @@ export default function Home({ params }: roomProps) {
|
||||||
socketRef.current.emit("player_choice", {roomId: id, choice: playerName, player: name})
|
socketRef.current.emit("player_choice", {roomId: id, choice: playerName, player: name})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setAndSendPhoto(mode){
|
||||||
|
console.log(mode)
|
||||||
|
if(mode == "webcam"){
|
||||||
|
const imageSrc = webcamRef.current.getScreenshot()
|
||||||
|
resizeBase64Image(imageSrc).then((data) => {
|
||||||
|
setQuestionReply({photo: data})
|
||||||
|
socketRef.current.emit("question_reply", { roomId: id, data:{photo: data}})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(mode == "file"){
|
||||||
|
getBase64OfImage(inputPhotoRef.current.files[0], (data) => resizeBase64Image(data).then((data) =>{
|
||||||
|
setQuestionReply({photo: data})
|
||||||
|
socketRef.current.emit("question_reply", { roomId: id, data:{photo: data}})
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="flex min-h-screen flex-col items-center space-y-16 p-4">
|
<main className="flex min-h-screen flex-col items-center space-y-16 p-4">
|
||||||
|
<dialog className="modal" ref={photoModalRef}>
|
||||||
|
<div className="modal-box w-full h-full">
|
||||||
|
<Webcam ref={webcamRef} />
|
||||||
|
<div className="modal-action">
|
||||||
|
<form method="dialog">
|
||||||
|
{/* if there is a button, it will close the modal */}
|
||||||
|
<button className="btn" onClick={() => setAndSendPhoto("webcam")}>Close</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
{ !gameStarted &&
|
{ !gameStarted &&
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
|
@ -231,7 +270,7 @@ export default function Home({ params }: roomProps) {
|
||||||
{ gameStarted &&
|
{ gameStarted &&
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col space-y-4 items-center">
|
<div className="flex flex-col space-y-4 items-center">
|
||||||
<h1 className="text-3xl">{questionDisplayed}</h1>
|
<h1 className="text-3xl">{questionDisplayed.text}</h1>
|
||||||
<span className="indicator-item badge indicator-bottom indicator-center opacity-30">{questionNbr}/{questionLimit}</span>
|
<span className="indicator-item badge indicator-bottom indicator-center opacity-30">{questionNbr}/{questionLimit}</span>
|
||||||
</div>
|
</div>
|
||||||
{ countdown > 0 &&
|
{ countdown > 0 &&
|
||||||
|
@ -269,6 +308,43 @@ export default function Home({ params }: roomProps) {
|
||||||
</div>
|
</div>
|
||||||
)})}
|
)})}
|
||||||
</div>
|
</div>
|
||||||
|
{ (questionDisplayed.type == "photo" && possibleChoice.sort((a,b) => b.nbrVotes - a.nbrVotes)[0].browserId == browserId) &&
|
||||||
|
<>
|
||||||
|
{ questionReply.photo == undefined &&
|
||||||
|
<div className="flex flex-col items-center space-y-4">
|
||||||
|
<span className="text-xl">À toi d'envoyer une photo !</span>
|
||||||
|
<input type="file" ref={inputPhotoRef} onChange={() => setAndSendPhoto("file")} className="hidden" />
|
||||||
|
<div className="flex flex-row space-x-4">
|
||||||
|
<button className="btn btn-primary" onClick={() => inputPhotoRef.current.click()}><IconPhotoUp /></button>
|
||||||
|
<button className="btn btn-primary" onClick={() => photoModalRef.current.showModal()}><IconCamera /></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{ questionReply.photo != undefined &&
|
||||||
|
<div>
|
||||||
|
<img src={questionReply.photo} />
|
||||||
|
<span className="text-zinc-500">Photo received from {possibleChoice.sort((a,b) => b.nbrVotes - a.nbrVotes)[0].name}...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
{ (questionDisplayed.type == "photo" && possibleChoice.sort((a,b) => b.nbrVotes - a.nbrVotes)[0].browserId != browserId) &&
|
||||||
|
<>
|
||||||
|
{ questionReply.photo == undefined &&
|
||||||
|
<div>
|
||||||
|
<span className="text-zinc-500">Waiting for {possibleChoice.sort((a,b) => b.nbrVotes - a.nbrVotes)[0].name}...</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{ questionReply.photo != undefined &&
|
||||||
|
<div>
|
||||||
|
<img src={questionReply.photo} />
|
||||||
|
<span className="text-zinc-500">Photo received from {possibleChoice.sort((a,b) => b.nbrVotes - a.nbrVotes)[0].name}...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
{ (role == "owner" && questionNbr < questionLimit) &&
|
{ (role == "owner" && questionNbr < questionLimit) &&
|
||||||
<button className="btn btn-primary" onClick={nextQuestion}>Next question</button>
|
<button className="btn btn-primary" onClick={nextQuestion}>Next question</button>
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,57 +45,57 @@ export const questions = [
|
||||||
//"Qui a le plus de connaissances historiques ?",
|
//"Qui a le plus de connaissances historiques ?",
|
||||||
//"Qui est le/la plus passionné·e de jardinage ?",
|
//"Qui est le/la plus passionné·e de jardinage ?",
|
||||||
//"Qui a les meilleurs talents d'acteur·rice ?",
|
//"Qui a les meilleurs talents d'acteur·rice ?",
|
||||||
"Qui va sauter dans la piscine ?",
|
{ text: "Qui va sauter dans la piscine ?", type: "text"},
|
||||||
"Qui date le plus âgé ?",
|
{ text: "Qui date le plus âgé ?", type: "text"},
|
||||||
"Qui est le plus flexible avec démonstration ?",
|
{ text: "Qui est le plus flexible avec démonstration ?", type: "text"},
|
||||||
"Qui va faire un striptease ?",
|
{ text: "Qui va faire un striptease ?", type:"text"},
|
||||||
"Qui sera la pire parent ?",
|
{ text: "Qui sera la pire parent ?", type:"text"},
|
||||||
"Qui est le plus alcoolique ?",
|
{ text: "Qui est le plus alcoolique ?", type:"text"},
|
||||||
"Qui serait capable de chier dans la seine ?",
|
{ text: "Qui serait capable de chier dans la seine ?", type:"text"},
|
||||||
"Qui va montrer son dernier message envoyé ?",
|
{ text: "Qui va montrer son dernier message envoyé ?", type:"text"},
|
||||||
"Qui va faire une roulette de photos ?",
|
{ text: "Qui va faire une roulette de photos ?", type:"text"},
|
||||||
"Qui a déjà bouffé les deux boules d'un mec ?",
|
{ text: "Qui a déjà bouffé les deux boules d'un mec ?", type:"text"},
|
||||||
"Qui va nous décrire son crush ?",
|
{ text: "Qui va nous décrire son crush ?", type: "text"},
|
||||||
"Qui est le plus addict ?",
|
{ text: "Qui est le plus addict ?", type: "text"},
|
||||||
"Qui est le plus croquant ?",
|
{ text: "Qui est le plus croquant ?", type: "text"},
|
||||||
"Qui s'auto-suce le plus ?",
|
{ text: "Qui s'auto-suce le plus ?", type: "text"},
|
||||||
"Qui va prendre une fessée avec la tongue de l'archi Vergnaud ?",
|
{ text: "Qui va prendre une fessée avec la tongue de l'archi Vergnaud ?", type: "text"},
|
||||||
"Qui est le plus à droite ?",
|
{ text: "Qui est le plus à droite ?", type: "text"},
|
||||||
"Qui conduit le mieux ?",
|
{ text: "Qui conduit le mieux ?", type: "text"},
|
||||||
"Qui gagne au bras de fer ? (Preuve)",
|
{ text: "Qui gagne au bras de fer ? (Preuve)", type: "text"},
|
||||||
"Qui va faire une roulade ?",
|
{ text: "Qui va faire une roulade ?", type: "text"},
|
||||||
"Qui a le plus une tête de con•ne ?",
|
{ text: "Qui a le plus une tête de con•ne ?", type: "text"},
|
||||||
"Qui est le meilleur menteur ?",
|
{ text: "Qui est le meilleur menteur ?", type: "text"},
|
||||||
"Qui rikou ?",
|
{ text: "Qui rikou ?", type: "text"},
|
||||||
"Qui va boire un shot d'huile ?",
|
{ text: "Qui va boire un shot d'huile ?", type: "text"},
|
||||||
"Qui va manger une cuillère a soupe de mayonnaise ?",
|
{ text: "Qui va manger une cuillère a soupe de mayonnaise ?", type: "text"},
|
||||||
"Qui va choisir ce que l'autre va manger ?",
|
{ text: "Qui va choisir ce que l'autre va manger ?", type: "text"},
|
||||||
"Qui va nous organiser les prochaines vacances ?",
|
{ text: "Qui va nous organiser les prochaines vacances ?", type: "text"},
|
||||||
"Qui a la plus belle fesse ?",
|
{ text: "Qui a la plus belle fesse ?", type: "text"},
|
||||||
"Qui est le plus intrusif ?",
|
{ text: "Qui est le plus intrusif ?", type: "text"},
|
||||||
"Qui a le plus haut bodycount ?",
|
{ text: "Qui a le plus haut bodycount ?", type: "text"},
|
||||||
"Qui va imiter Nicolas Pham ?",
|
{ text: "Qui va imiter Nicolas Pham ?", type: "text"},
|
||||||
"Qui va dire vinaigrette sans Vi ?",
|
{ text: "Qui va dire vinaigrette sans Vi ?", type: "text"},
|
||||||
"Qui va faire son âge divisé par deux en pompes ?",
|
{ text: "Qui va faire son âge divisé par deux en pompes ?", type: "text"},
|
||||||
"Qui va faire l'intro pour le dernier tiktok ?",
|
{ text: "Qui va faire l'intro pour le dernier tiktok ?", type: "text"},
|
||||||
"Qui va faire une photo sexy avec son voisin de droite ?",
|
{ text: "Qui va faire une photo sexy avec son voisin de droite ?", type: "photo"},
|
||||||
"Qui va brouter de l'herbe ?",
|
{ text: "Qui va brouter de l'herbe ?", type: "text"},
|
||||||
"Qui va boire un Ricard piscine ?",
|
{ text: "Qui va boire un Ricard piscine ?", type: "text"},
|
||||||
"Qui est susceptible de se marier ?",
|
{ text: "Qui est susceptible de se marier ?", type: "text"},
|
||||||
"À qui donneriez vous vos enfants ?",
|
{ text: "À qui donneriez vous vos enfants ?", type: "text"},
|
||||||
"Qui serait le meilleur DDP ?",
|
{ text: "Qui serait le meilleur DDP ?", type: "text"},
|
||||||
"À qui tu te confierais le plus ?",
|
{ text: "À qui tu te confierais le plus ?", type: "text"},
|
||||||
"Qui est le plus béru ?",
|
{ text: "Qui est le plus béru ?", type: "text"},
|
||||||
"Qui est le plus kinky ?",
|
{ text: "Qui est le plus kinky ?", type: "text"},
|
||||||
"Qui va nous chanter le menu ?",
|
{ text: "Qui va nous chanter le menu ?", type: "text"},
|
||||||
"Qui lance un monôme tout nu ?",
|
{ text: "Qui lance un monôme tout nu ?", type: "text"},
|
||||||
"Qui est le plus rapide ?",
|
{ text: "Qui est le plus rapide ?", type: "text"},
|
||||||
"Qui est le plus susceptible d'être célèbre ?",
|
{ text: "Qui est le plus susceptible d'être célèbre ?", type: "text"},
|
||||||
"Qui est le plus romantique ?",
|
{ text: "Qui est le plus romantique ?", type: "text"},
|
||||||
"Qui va raconter la chose la plus folle de sa vie ?",
|
{ text: "Qui va raconter la chose la plus folle de sa vie ?", type: "text"},
|
||||||
"Qui se masturbe le plus ?",
|
{ text: "Qui se masturbe le plus ?", type: "text"},
|
||||||
"Qui est le plus gros fan de star wars ?",
|
{ text: "Qui est le plus gros fan de star wars ?", type: "text"},
|
||||||
"Qui a pleuré en dernier ?",
|
{ text: "Qui a pleuré en dernier ?", type: "text"},
|
||||||
]
|
]
|
||||||
|
|
||||||
export function getRandomQuestion(alreadyDone = []){
|
export function getRandomQuestion(alreadyDone = []){
|
||||||
|
|
36
app/page.tsx
36
app/page.tsx
|
@ -5,6 +5,7 @@ import { useState, useEffect, useRef } from 'react'
|
||||||
import { IconPencilMinus, IconCamera, IconDice6 } from "@tabler/icons-react"
|
import { IconPencilMinus, IconCamera, IconDice6 } from "@tabler/icons-react"
|
||||||
import { defaultAvatarImage } from './avatarImage'
|
import { defaultAvatarImage } from './avatarImage'
|
||||||
import { getUsername } from './usernameGenerate'
|
import { getUsername } from './usernameGenerate'
|
||||||
|
import { resizeBase64Image, getBase64OfImage } from './utils'
|
||||||
import Webcam from 'react-webcam'
|
import Webcam from 'react-webcam'
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
@ -40,41 +41,6 @@ export default function Home() {
|
||||||
setShowWebcam(false)
|
setShowWebcam(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBase64OfImage(file, cb) {
|
|
||||||
let reader = new FileReader();
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
reader.onload = function () {
|
|
||||||
cb(reader.result)
|
|
||||||
};
|
|
||||||
reader.onerror = function (error) {
|
|
||||||
console.log('Error: ', error);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function resizeBase64Image(base64Image) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const maxSizeInKB = 500;
|
|
||||||
const maxSizeInBytes = maxSizeInKB * 1024;
|
|
||||||
const img = new Image();
|
|
||||||
img.src = base64Image;
|
|
||||||
img.onload = function () {
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
const width = img.width;
|
|
||||||
const height = img.height;
|
|
||||||
const aspectRatio = width / height;
|
|
||||||
const newWidth = Math.sqrt(maxSizeInBytes * aspectRatio);
|
|
||||||
const newHeight = Math.sqrt(maxSizeInBytes / aspectRatio);
|
|
||||||
canvas.width = newWidth;
|
|
||||||
canvas.height = newHeight;
|
|
||||||
ctx.drawImage(img, 0, 0, newWidth, newHeight);
|
|
||||||
let quality = 0.8;
|
|
||||||
let dataURL = canvas.toDataURL('image/jpeg', quality);
|
|
||||||
resolve(dataURL);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let localName = localStorage.getItem("name")
|
let localName = localStorage.getItem("name")
|
||||||
let localAvatar = localStorage.getItem("avatar")
|
let localAvatar = localStorage.getItem("avatar")
|
||||||
|
|
36
app/utils.ts
Normal file
36
app/utils.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
export function resizeBase64Image(base64Image) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const maxSizeInKB = 500;
|
||||||
|
const maxSizeInBytes = maxSizeInKB * 1024;
|
||||||
|
const img = new Image();
|
||||||
|
img.src = base64Image;
|
||||||
|
img.onload = function () {
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
const width = img.width;
|
||||||
|
const height = img.height;
|
||||||
|
const aspectRatio = width / height;
|
||||||
|
const newWidth = Math.sqrt(maxSizeInBytes * aspectRatio);
|
||||||
|
const newHeight = Math.sqrt(maxSizeInBytes / aspectRatio);
|
||||||
|
canvas.width = newWidth;
|
||||||
|
canvas.height = newHeight;
|
||||||
|
ctx.drawImage(img, 0, 0, newWidth, newHeight);
|
||||||
|
let quality = 0.8;
|
||||||
|
let dataURL = canvas.toDataURL('image/jpeg', quality);
|
||||||
|
resolve(dataURL);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBase64OfImage(file, cb) {
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.onload = function () {
|
||||||
|
cb(reader.result)
|
||||||
|
};
|
||||||
|
reader.onerror = function (error) {
|
||||||
|
console.log('Error: ', error);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,10 @@ app.prepare().then(() => {
|
||||||
socket.to(params.roomId).emit("next_question",{possibleChoice: params.possibleChoice, question: params.question, duration: params.duration})
|
socket.to(params.roomId).emit("next_question",{possibleChoice: params.possibleChoice, question: params.question, duration: params.duration})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
socket.on("question_reply", (params) => {
|
||||||
|
socket.to(params.roomId).emit("question_reply", params.data)
|
||||||
|
})
|
||||||
|
|
||||||
socket.on("player_choice", (params) => {
|
socket.on("player_choice", (params) => {
|
||||||
console.log(params)
|
console.log(params)
|
||||||
socket.to(params.roomId).emit("player_choice", {choice: params.choice, player: params.player})
|
socket.to(params.roomId).emit("player_choice", {choice: params.choice, player: params.player})
|
||||||
|
|
Loading…
Reference in a new issue