From 012caef5060ee876e5dfd6d4defd1795fce30d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucien=20Asti=C3=A9?= <lucien@MacBook-Air-de-Lucien.local> Date: Fri, 9 Aug 2024 14:38:16 +0200 Subject: [PATCH] Add avatar image + generateur de pseudo --- app/[id]/page.tsx | 36 +++++++++------- app/avatarImage.ts | 1 + app/page.tsx | 94 ++++++++++++++++++++++++++++++++++++++--- app/usernameGenerate.ts | 25 +++++++++++ package-lock.json | 11 +++++ package.json | 1 + server.mjs | 21 ++++----- 7 files changed, 159 insertions(+), 30 deletions(-) create mode 100644 app/avatarImage.ts create mode 100644 app/usernameGenerate.ts diff --git a/app/[id]/page.tsx b/app/[id]/page.tsx index dca3fa4..7c88966 100644 --- a/app/[id]/page.tsx +++ b/app/[id]/page.tsx @@ -4,6 +4,7 @@ import { io } from "socket.io-client" import { getRandomQuestion } from "./questions" import { useForceUpdate } from "./forceUpdate" import { IconCrown } from "@tabler/icons-react" +import { defaultAvatarImage } from '../avatarImage' interface roomProps { params: { @@ -17,6 +18,7 @@ export default function Home({ params }: roomProps) { const [role, setRole] = useState("") const [name, setName] = useState("") + const [avatar, setAvatar] = useState(defaultAvatarImage) const [gameStarted, setGameStarted] = useState(false) const [gameEnded, setGameEnded] = useState(false) @@ -37,14 +39,16 @@ export default function Home({ params }: roomProps) { const roomNameDisplay = id.substring(0,3) + " " + id.substring(3,6) useEffect(() => { - const username = localStorage.getItem('name') - setName(username) + const localName = localStorage.getItem('name') + setName(localName) + const localAvatar = localStorage.getItem('avatar') + setAvatar(localAvatar) // Listen for incoming setMessages socketRef.current = io("ws://localhost:3000"); socketRef.current.on("connect", () => { setIsConnected(true) - socketRef.current.emit('room_connect', {"id": id, "name": username}) + socketRef.current.emit('room_connect', {id: id, name: localName, avatar: localAvatar}) }); socketRef.current.on("new_player", (params) => { @@ -195,19 +199,21 @@ export default function Home({ params }: roomProps) { } { (isConnected && players.length > 0) && <div className="flex flex-col space-y-16"> - <div> + <div className="grid grid-cols-3 gap-4"> { players.map((player) => { - console.log(player) - if(player.role == "player") { - return ( - <p>{player.name}</p> - ) - } - if(player.role == "owner") { - return ( - <p className="flex flex-row">{player.name}<IconCrown /></p> - ) - } + return ( + <> + <div className="flex flex-col items-center"> + <div className="avatar indicator"> + {player.role == "owner" && <IconCrown className="indicator-item" />} + <div className="w-16 rounded"> + <img src={player.avatar} /> + </div> + </div> + <p className="flex flex-row">{player.name}</p> + </div> + </> + ) })} </div> { role == "owner" && diff --git a/app/avatarImage.ts b/app/avatarImage.ts new file mode 100644 index 0000000..9a72002 --- /dev/null +++ b/app/avatarImage.ts @@ -0,0 +1 @@ +export const defaultAvatarImage = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEBLAEsAAD/4QBWRXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAAITAAMAAAABAAEAAAAAAAAAAAEsAAAAAQAAASwAAAAB/+0ALFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAPHAFaAAMbJUccAQAAAgAEAP/hDW5odHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvADw/eHBhY2tldCBiZWdpbj0n77u/JyBpZD0nVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkJz8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0nYWRvYmU6bnM6bWV0YS8nIHg6eG1wdGs9J0ltYWdlOjpFeGlmVG9vbCAxMS44OCc+CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyc+CgogPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9JycKICB4bWxuczp0aWZmPSdodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyc+CiAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICA8dGlmZjpYUmVzb2x1dGlvbj4zMDAvMTwvdGlmZjpYUmVzb2x1dGlvbj4KICA8dGlmZjpZUmVzb2x1dGlvbj4zMDAvMTwvdGlmZjpZUmVzb2x1dGlvbj4KIDwvcmRmOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PScnCiAgeG1sbnM6eG1wPSdodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvJz4KICA8eG1wOkNyZWF0b3JUb29sPkFkb2JlIFN0b2NrIFBsYXRmb3JtPC94bXA6Q3JlYXRvclRvb2w+CiA8L3JkZjpEZXNjcmlwdGlvbj4KCiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0nJwogIHhtbG5zOnhtcE1NPSdodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vJz4KICA8eG1wTU06RG9jdW1lbnRJRD54bXAuaWlkOmFhNGI1ZWU1LTAxMDUtNDZmNS1hN2Y4LTBmYWEwMWY2NDczODwveG1wTU06RG9jdW1lbnRJRD4KICA8eG1wTU06SW5zdGFuY2VJRD5hZG9iZTpkb2NpZDpzdG9jazo4ZGM0ODU1Ni05ZmRkLTRiNGMtYThmOC1jYTlkNTVjODQ2YTE8L3htcE1NOkluc3RhbmNlSUQ+CiAgPHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpzdG9jazo1NDk5ODM5NzA8L3htcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD4KIDwvcmRmOkRlc2NyaXB0aW9uPgo8L3JkZjpSREY+CjwveDp4bXBtZXRhPgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSd3Jz8+/9sAQwAF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" diff --git a/app/page.tsx b/app/page.tsx index 5672327..b3634c3 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -2,10 +2,16 @@ import { navigate } from './action' import { useState, useEffect, useRef } from 'react' -import { IconPencilMinus } from "@tabler/icons-react" +import { IconPencilMinus, IconCamera, IconDice6 } from "@tabler/icons-react" +import { defaultAvatarImage } from './avatarImage' +import { getUsername } from './usernameGenerate' +import Webcam from 'react-webcam' export default function Home() { const [name, setName] = useState("") + const [avatar, setAvatar] = useState(defaultAvatarImage) + const [showWebcam, setShowWebcam] = useState(false) + const webcamRef = useRef() const modal = useRef() const inputName = useRef() @@ -14,35 +20,113 @@ export default function Home() { localStorage.setItem("name", inputName.current.value) } + function setAndStoreAvatar(data){ + resizeBase64Image(data).then((data) => { + localStorage.setItem("avatar", data) + setAvatar(data) + }) + } + + function takePictureAvatar() { + const imageSrc = webcamRef.current.getScreenshot() + setAndStoreAvatar(imageSrc) + 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") if(localName != null){ setName(localName) } else { modal.current.showModal() } + + if(localAvatar != null) { + setAvatar(localAvatar) + } }, []) return ( <main data-theme="light" className="flex min-h-screen flex-col items-center space-y-16 p-24"> <dialog ref={modal} className="modal"> - <div className="modal-box"> - <label className="form-control w-full max-w-xs"> + <div className="modal-box flex flex-col space-y-4"> + <div className="avatar flex flex-col items-center space-y-4"> + <div className="w-24 rounded"> + <img src={avatar} /> + </div> + { showWebcam && + <> + <Webcam ref={webcamRef} /> + <button className="btn btn-primary" onClick={takePictureAvatar}><IconCamera /></button> + </> + } + { !showWebcam && + <> + <button className="btn btn-primary" onClick={() => {setShowWebcam(true)}}>Use Webcam</button> + <input type="file" onChange={(e) => {getBase64OfImage(e.target.files[0], (data) => setAndStoreAvatar(data))}} className="file-input w-full max-w-xs"/> + </> + } + </div> + <label className="form-control w-full"> <div className="label"> <span className="label-text">What is your name?</span> </div> - <input type="text" ref={inputName} defaultValue={name} placeholder="Name" className="input input-bordered w-full max-w-xs" /> + <div className="flex flex-row w-full space-x-4"> + <input type="text" ref={inputName} defaultValue={name} placeholder="Name" className="input input-bordered w-full" /> + <button onClick={() => {inputName.current.value = getUsername()}} ><IconDice6 /></button> + </div> </label> <div className="modal-action"> <form method="dialog"> {/* if there is a button in form, it will close the modal */} - <button onClick={setUsername} className="btn">Close</button> + <button onClick={setUsername} className="btn">Save</button> </form> </div> </div> </dialog> <h1 className="text-3xl">Bazaar</h1> <div className="flex flex-col space-y-4 items-center"> + <div className="avatar"> + <div className="w-24 rounded"> + <img src={avatar} /> + </div> + </div> <div className="flex flex-row space-x-4"> <span className="text-xl">{name}</span> <button onClick={() => { modal.current.showModal()}}> diff --git a/app/usernameGenerate.ts b/app/usernameGenerate.ts new file mode 100644 index 0000000..80e0d96 --- /dev/null +++ b/app/usernameGenerate.ts @@ -0,0 +1,25 @@ +const prenom = [ + "Stéphane", + "Hubert", + "Alphonse", + "Marjolaine", + "Cathy", + "Patrick", + "Agathe", + "Erneste", +] + +const nom = [ + "Falzar", + "Globule", + "Bermuda", + "Zigounette", + "Pissenlit", + "Détritus", +] + +export function getUsername(){ + const prenomIndex = Math.floor(Math.random() * prenom.length) + const nomIndex = Math.floor(Math.random() * nom.length) + return prenom[prenomIndex] + " " + nom[nomIndex] +} diff --git a/package-lock.json b/package-lock.json index 075fc7f..ab0c254 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "next": "14.2.5", "react": "^18", "react-dom": "^18", + "react-webcam": "^7.2.0", "socket.io": "^4.7.5", "socket.io-client": "^4.7.5" }, @@ -4272,6 +4273,16 @@ "dev": true, "license": "MIT" }, + "node_modules/react-webcam": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/react-webcam/-/react-webcam-7.2.0.tgz", + "integrity": "sha512-xkrzYPqa1ag2DP+2Q/kLKBmCIfEx49bVdgCCCcZf88oF+0NPEbkwYk3/s/C7Zy0mhM8k+hpdNkBLzxg8H0aWcg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.2.0", + "react-dom": ">=16.2.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index e9658ec..45e0f6a 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "next": "14.2.5", "react": "^18", "react-dom": "^18", + "react-webcam": "^7.2.0", "socket.io": "^4.7.5", "socket.io-client": "^4.7.5" }, diff --git a/server.mjs b/server.mjs index 1cfa3a5..d98f06a 100644 --- a/server.mjs +++ b/server.mjs @@ -18,18 +18,19 @@ app.prepare().then(() => { io.on("connection", (socket) => { console.log("User connected " + socket.id) - socket.on('room_connect', (room) => { - if(!Object.keys(active_rooms).includes(room.id)){ - console.log("First person joined " + room.id + " ! " + room.name + " is owner.") - active_rooms[room.id] = [{id: socket.id, name: room.name, role: "owner", vote: ""}] - socket.emit("room_joined", {"room_users": active_rooms[room.id], "role": "owner"}) + + socket.on('room_connect', (params) => { + if(!Object.keys(active_rooms).includes(params.id)){ + console.log("First person joined " + params.id + " ! " + params.name + " is owner.") + active_rooms[params.id] = [{id: socket.id, name: params.name, avatar: params.avatar, role: "owner", vote: ""}] + socket.emit("room_joined", {"room_users": active_rooms[params.id], "role": "owner"}) } else { - socket.to(room.id).emit("new_player",{"id": socket.id, "name": room.name, role: "player"}) - active_rooms[room.id].push({id: socket.id, name: room.name, role: "player", vote: ""}) - socket.emit("room_joined", {"room_users": active_rooms[room.id], role: "player"}) - console.log("New person joined " + room.id + " ! " + room.name + " is player.") + socket.to(params.id).emit("new_player",{"id": socket.id, "name": params.name, avatar: params.avatar, role: "player"}) + active_rooms[params.id].push({id: socket.id, name: params.name, avatar: params.avatar, role: "player", vote: ""}) + socket.emit("room_joined", {"room_users": active_rooms[params.id], role: "player"}) + console.log("New person joined " + params.id + " ! " + params.name + " is player.") } - socket.join(room.id) + socket.join(params.id) }) socket.on("start_game", (params) => {