2024-08-08 20:21:01 +00:00
|
|
|
'use client'
|
|
|
|
|
|
|
|
import { navigate } from './action'
|
|
|
|
import { useState, useEffect, useRef } from 'react'
|
2024-08-09 12:38:16 +00:00
|
|
|
import { IconPencilMinus, IconCamera, IconDice6 } from "@tabler/icons-react"
|
|
|
|
import { defaultAvatarImage } from './avatarImage'
|
|
|
|
import { getUsername } from './usernameGenerate'
|
|
|
|
import Webcam from 'react-webcam'
|
2024-08-08 20:21:01 +00:00
|
|
|
|
|
|
|
export default function Home() {
|
|
|
|
const [name, setName] = useState("")
|
2024-08-09 12:38:16 +00:00
|
|
|
const [avatar, setAvatar] = useState(defaultAvatarImage)
|
2024-08-09 16:35:57 +00:00
|
|
|
const [browserId, setBrowserId] = useState("")
|
2024-08-09 12:38:16 +00:00
|
|
|
const [showWebcam, setShowWebcam] = useState(false)
|
|
|
|
const webcamRef = useRef()
|
2024-08-08 20:21:01 +00:00
|
|
|
const modal = useRef()
|
|
|
|
const inputName = useRef()
|
|
|
|
|
|
|
|
function setUsername() {
|
|
|
|
setName(inputName.current.value)
|
|
|
|
localStorage.setItem("name", inputName.current.value)
|
|
|
|
}
|
|
|
|
|
2024-08-09 12:38:16 +00:00
|
|
|
function setAndStoreAvatar(data){
|
|
|
|
resizeBase64Image(data).then((data) => {
|
|
|
|
localStorage.setItem("avatar", data)
|
|
|
|
setAvatar(data)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-08-09 16:35:57 +00:00
|
|
|
function uuidv4() {
|
|
|
|
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, c =>
|
|
|
|
(+c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> +c / 4).toString(16)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-08-09 12:38:16 +00:00
|
|
|
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);
|
|
|
|
};
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-08-08 20:21:01 +00:00
|
|
|
useEffect(() => {
|
|
|
|
let localName = localStorage.getItem("name")
|
2024-08-09 12:38:16 +00:00
|
|
|
let localAvatar = localStorage.getItem("avatar")
|
2024-08-09 16:35:57 +00:00
|
|
|
let localBrowserId = localStorage.getItem("browserId")
|
2024-08-08 20:21:01 +00:00
|
|
|
if(localName != null){
|
|
|
|
setName(localName)
|
|
|
|
} else {
|
|
|
|
modal.current.showModal()
|
|
|
|
}
|
2024-08-09 12:38:16 +00:00
|
|
|
|
|
|
|
if(localAvatar != null) {
|
|
|
|
setAvatar(localAvatar)
|
|
|
|
}
|
2024-08-09 16:35:57 +00:00
|
|
|
|
|
|
|
if(localBrowserId != null) {
|
|
|
|
setBrowserId(localBrowserId)
|
|
|
|
} else {
|
|
|
|
let uuid = uuidv4()
|
|
|
|
setBrowserId(uuid)
|
|
|
|
localStorage.setItem("browserId", uuid)
|
|
|
|
}
|
2024-08-08 20:21:01 +00:00
|
|
|
}, [])
|
|
|
|
|
|
|
|
return (
|
|
|
|
<main data-theme="light" className="flex min-h-screen flex-col items-center space-y-16 p-24">
|
|
|
|
<dialog ref={modal} className="modal">
|
2024-08-09 12:38:16 +00:00
|
|
|
<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">
|
2024-08-08 20:21:01 +00:00
|
|
|
<div className="label">
|
|
|
|
<span className="label-text">What is your name?</span>
|
|
|
|
</div>
|
2024-08-09 12:38:16 +00:00
|
|
|
<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>
|
2024-08-08 20:21:01 +00:00
|
|
|
</label>
|
|
|
|
<div className="modal-action">
|
|
|
|
<form method="dialog">
|
|
|
|
{/* if there is a button in form, it will close the modal */}
|
2024-08-09 12:38:16 +00:00
|
|
|
<button onClick={setUsername} className="btn">Save</button>
|
2024-08-08 20:21:01 +00:00
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</dialog>
|
|
|
|
<h1 className="text-3xl">Bazaar</h1>
|
|
|
|
<div className="flex flex-col space-y-4 items-center">
|
2024-08-09 12:38:16 +00:00
|
|
|
<div className="avatar">
|
|
|
|
<div className="w-24 rounded">
|
|
|
|
<img src={avatar} />
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-08-08 20:21:01 +00:00
|
|
|
<div className="flex flex-row space-x-4">
|
|
|
|
<span className="text-xl">{name}</span>
|
|
|
|
<button onClick={() => { modal.current.showModal()}}>
|
|
|
|
<IconPencilMinus />
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div className="flex flex-col space-y-4 items-center">
|
|
|
|
<a href="/random" className="btn btn-primary">Create a room</a>
|
|
|
|
<div className="divider"></div>
|
|
|
|
<form action={navigate} className="flex flex-col space-y-4">
|
|
|
|
<input type="text" name="id" placeholder="Room pin" className="input input-bordered w-full max-w-xs" />
|
|
|
|
<button className="btn btn-primary">Join Room</button>
|
|
|
|
</form>
|
|
|
|
</div>
|
|
|
|
</main>
|
|
|
|
);
|
|
|
|
}
|