Add possibility to send picture through the app for certains questions

This commit is contained in:
Lucien Astié 2024-08-09 23:20:04 +02:00
parent cbd500e13b
commit 28e1a0c4f8
5 changed files with 171 additions and 89 deletions

View file

@ -3,8 +3,10 @@ import { useState, useEffect, useRef } from 'react'
import { io } from "socket.io-client"
import { getRandomQuestion } from "./questions"
import { useForceUpdate } from "./forceUpdate"
import { IconCrown } from "@tabler/icons-react"
import { IconCrown, IconPhotoUp, IconCamera } from "@tabler/icons-react"
import { defaultAvatarImage } from '../avatarImage'
import { resizeBase64Image, getBase64OfImage } from '../utils'
import Webcam from 'react-webcam'
interface roomProps {
params: {
@ -23,7 +25,8 @@ export default function Home({ params }: roomProps) {
const [gameStarted, setGameStarted] = useState(false)
const [gameEnded, setGameEnded] = useState(false)
const [questionDisplayed, setQuestionDisplayed] = useState("")
const [questionReply, setQuestionReply] = useState({})
const [questionDisplayed, setQuestionDisplayed] = useState({})
const [possibleChoice, setPossibleChoice] = useState([])
const [totalVotes, setTotalVotes] = useState(0)
const [choice, setChoice] = useState("")
@ -33,6 +36,9 @@ export default function Home({ params }: roomProps) {
const [questionAlreadyDone, setQuestionAlreadyDone] = useState([])
const socketRef = useRef()
const inputPhotoRef = useRef()
const photoModalRef = useRef()
const webcamRef = useRef()
const duration = 15
const questionLimit = 10
@ -76,6 +82,11 @@ export default function Home({ params }: roomProps) {
setTotalVotes(0)
})
socketRef.current.on("question_reply", (params) => {
console.log(params)
setQuestionReply(params)
})
socketRef.current.on("reset_game", (params) => {
setGameStarted(false)
setCountdown(0)
@ -187,8 +198,36 @@ export default function Home({ params }: roomProps) {
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 (
<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 &&
<>
<div className="flex flex-col">
@ -231,7 +270,7 @@ export default function Home({ params }: roomProps) {
{ gameStarted &&
<>
<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>
</div>
{ countdown > 0 &&
@ -269,6 +308,43 @@ export default function Home({ params }: roomProps) {
</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) &&
<button className="btn btn-primary" onClick={nextQuestion}>Next question</button>
}

View file

@ -45,57 +45,57 @@ export const questions = [
//"Qui a le plus de connaissances historiques ?",
//"Qui est le/la plus passionné·e de jardinage ?",
//"Qui a les meilleurs talents d'acteur·rice ?",
"Qui va sauter dans la piscine ?",
"Qui date le plus âgé ?",
"Qui est le plus flexible avec démonstration ?",
"Qui va faire un striptease ?",
"Qui sera la pire parent ?",
"Qui est le plus alcoolique ?",
"Qui serait capable de chier dans la seine ?",
"Qui va montrer son dernier message envoyé ?",
"Qui va faire une roulette de photos ?",
"Qui a déjà bouffé les deux boules d'un mec ?",
"Qui va nous décrire son crush ?",
"Qui est le plus addict ?",
"Qui est le plus croquant ?",
"Qui s'auto-suce le plus ?",
"Qui va prendre une fessée avec la tongue de l'archi Vergnaud ?",
"Qui est le plus à droite ?",
"Qui conduit le mieux ?",
"Qui gagne au bras de fer ? (Preuve)",
"Qui va faire une roulade ?",
"Qui a le plus une tête de con•ne ?",
"Qui est le meilleur menteur ?",
"Qui rikou ?",
"Qui va boire un shot d'huile ?",
"Qui va manger une cuillère a soupe de mayonnaise ?",
"Qui va choisir ce que l'autre va manger ?",
"Qui va nous organiser les prochaines vacances ?",
"Qui a la plus belle fesse ?",
"Qui est le plus intrusif ?",
"Qui a le plus haut bodycount ?",
"Qui va imiter Nicolas Pham ?",
"Qui va dire vinaigrette sans Vi ?",
"Qui va faire son âge divisé par deux en pompes ?",
"Qui va faire l'intro pour le dernier tiktok ?",
"Qui va faire une photo sexy avec son voisin de droite ?",
"Qui va brouter de l'herbe ?",
"Qui va boire un Ricard piscine ?",
"Qui est susceptible de se marier ?",
"À qui donneriez vous vos enfants ?",
"Qui serait le meilleur DDP ?",
"À qui tu te confierais le plus ?",
"Qui est le plus béru ?",
"Qui est le plus kinky ?",
"Qui va nous chanter le menu ?",
"Qui lance un monôme tout nu ?",
"Qui est le plus rapide ?",
"Qui est le plus susceptible d'être célèbre ?",
"Qui est le plus romantique ?",
"Qui va raconter la chose la plus folle de sa vie ?",
"Qui se masturbe le plus ?",
"Qui est le plus gros fan de star wars ?",
"Qui a pleuré en dernier ?",
{ text: "Qui va sauter dans la piscine ?", type: "text"},
{ text: "Qui date le plus âgé ?", type: "text"},
{ text: "Qui est le plus flexible avec démonstration ?", type: "text"},
{ text: "Qui va faire un striptease ?", type:"text"},
{ text: "Qui sera la pire parent ?", type:"text"},
{ text: "Qui est le plus alcoolique ?", type:"text"},
{ text: "Qui serait capable de chier dans la seine ?", type:"text"},
{ text: "Qui va montrer son dernier message envoyé ?", type:"text"},
{ text: "Qui va faire une roulette de photos ?", type:"text"},
{ text: "Qui a déjà bouffé les deux boules d'un mec ?", type:"text"},
{ text: "Qui va nous décrire son crush ?", type: "text"},
{ text: "Qui est le plus addict ?", type: "text"},
{ text: "Qui est le plus croquant ?", type: "text"},
{ text: "Qui s'auto-suce le plus ?", type: "text"},
{ text: "Qui va prendre une fessée avec la tongue de l'archi Vergnaud ?", type: "text"},
{ text: "Qui est le plus à droite ?", type: "text"},
{ text: "Qui conduit le mieux ?", type: "text"},
{ text: "Qui gagne au bras de fer ? (Preuve)", type: "text"},
{ text: "Qui va faire une roulade ?", type: "text"},
{ text: "Qui a le plus une tête de con•ne ?", type: "text"},
{ text: "Qui est le meilleur menteur ?", type: "text"},
{ text: "Qui rikou ?", type: "text"},
{ text: "Qui va boire un shot d'huile ?", type: "text"},
{ text: "Qui va manger une cuillère a soupe de mayonnaise ?", type: "text"},
{ text: "Qui va choisir ce que l'autre va manger ?", type: "text"},
{ text: "Qui va nous organiser les prochaines vacances ?", type: "text"},
{ text: "Qui a la plus belle fesse ?", type: "text"},
{ text: "Qui est le plus intrusif ?", type: "text"},
{ text: "Qui a le plus haut bodycount ?", type: "text"},
{ text: "Qui va imiter Nicolas Pham ?", type: "text"},
{ text: "Qui va dire vinaigrette sans Vi ?", type: "text"},
{ text: "Qui va faire son âge divisé par deux en pompes ?", type: "text"},
{ text: "Qui va faire l'intro pour le dernier tiktok ?", type: "text"},
{ text: "Qui va faire une photo sexy avec son voisin de droite ?", type: "photo"},
{ text: "Qui va brouter de l'herbe ?", type: "text"},
{ text: "Qui va boire un Ricard piscine ?", type: "text"},
{ text: "Qui est susceptible de se marier ?", type: "text"},
{ text: "À qui donneriez vous vos enfants ?", type: "text"},
{ text: "Qui serait le meilleur DDP ?", type: "text"},
{ text: "À qui tu te confierais le plus ?", type: "text"},
{ text: "Qui est le plus béru ?", type: "text"},
{ text: "Qui est le plus kinky ?", type: "text"},
{ text: "Qui va nous chanter le menu ?", type: "text"},
{ text: "Qui lance un monôme tout nu ?", type: "text"},
{ text: "Qui est le plus rapide ?", type: "text"},
{ text: "Qui est le plus susceptible d'être célèbre ?", type: "text"},
{ text: "Qui est le plus romantique ?", type: "text"},
{ text: "Qui va raconter la chose la plus folle de sa vie ?", type: "text"},
{ text: "Qui se masturbe le plus ?", type: "text"},
{ text: "Qui est le plus gros fan de star wars ?", type: "text"},
{ text: "Qui a pleuré en dernier ?", type: "text"},
]
export function getRandomQuestion(alreadyDone = []){

View file

@ -5,6 +5,7 @@ import { useState, useEffect, useRef } from 'react'
import { IconPencilMinus, IconCamera, IconDice6 } from "@tabler/icons-react"
import { defaultAvatarImage } from './avatarImage'
import { getUsername } from './usernameGenerate'
import { resizeBase64Image, getBase64OfImage } from './utils'
import Webcam from 'react-webcam'
export default function Home() {
@ -40,41 +41,6 @@ export default function Home() {
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(() => {
let localName = localStorage.getItem("name")
let localAvatar = localStorage.getItem("avatar")

36
app/utils.ts Normal file
View 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);
};
}

View file

@ -93,6 +93,10 @@ app.prepare().then(() => {
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) => {
console.log(params)
socket.to(params.roomId).emit("player_choice", {choice: params.choice, player: params.player})