|
"use client"; |
|
|
|
import { useState, useRef } from "react"; |
|
import { useParams, useRouter } from "next/navigation"; |
|
import { Button } from "@/components/ui/button"; |
|
import { Input } from "@/components/ui/input"; |
|
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; |
|
import { ArrowLeft, Mic, MicOff, RefreshCcw } from "lucide-react"; |
|
import Link from "next/link"; |
|
import "../../styles/background-pattern.css"; |
|
|
|
const avatars = [ |
|
"/avatar1.png", |
|
"/avatar2.png", |
|
"/avatar3.png", |
|
"/avatar4.png", |
|
"/avatar5.png", |
|
]; |
|
|
|
export default function JoinGroup() { |
|
const params = useParams(); |
|
const router = useRouter(); |
|
const [userName, setUserName] = useState(""); |
|
const [isRecording, setIsRecording] = useState(false); |
|
const [audioBlob, setAudioBlob] = useState<Blob | null>(null); |
|
const [isLoading, setIsLoading] = useState(false); |
|
const [avatarIndex, setAvatarIndex] = useState(0); |
|
const mediaRecorder = useRef<MediaRecorder | null>(null); |
|
const audioChunks = useRef<Blob[]>([]); |
|
|
|
const startRecording = async () => { |
|
try { |
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); |
|
mediaRecorder.current = new MediaRecorder(stream); |
|
audioChunks.current = []; |
|
|
|
mediaRecorder.current.ondataavailable = (event) => { |
|
audioChunks.current.push(event.data); |
|
}; |
|
|
|
mediaRecorder.current.onstop = () => { |
|
const audioBlob = new Blob(audioChunks.current, { type: "audio/wav" }); |
|
setAudioBlob(audioBlob); |
|
}; |
|
|
|
mediaRecorder.current.start(); |
|
setIsRecording(true); |
|
} catch (error) { |
|
console.error("Erreur lors de l'accès au microphone:", error); |
|
alert("Impossible d'accéder au microphone"); |
|
} |
|
}; |
|
|
|
const stopRecording = () => { |
|
if (mediaRecorder.current && isRecording) { |
|
mediaRecorder.current.stop(); |
|
setIsRecording(false); |
|
mediaRecorder.current.stream.getTracks().forEach((track) => track.stop()); |
|
} |
|
}; |
|
|
|
const changeAvatar = () => { |
|
setAvatarIndex((prevIndex) => (prevIndex + 1) % avatars.length); |
|
}; |
|
|
|
const handleSubmit = async (e: React.FormEvent) => { |
|
e.preventDefault(); |
|
if (!userName.trim() || !audioBlob) { |
|
alert("Veuillez entrer votre nom et enregistrer votre voix"); |
|
return; |
|
} |
|
|
|
setIsLoading(true); |
|
|
|
try { |
|
const formData = new FormData(); |
|
formData.append("audio", audioBlob); |
|
formData.append("name", userName); |
|
formData.append("avatar", avatars[avatarIndex]); |
|
|
|
const voiceResponse = await fetch("/api/voice", { |
|
method: "POST", |
|
body: formData, |
|
}); |
|
|
|
if (!voiceResponse.ok) |
|
throw new Error("Erreur lors de l'upload de la voix"); |
|
const userData = await voiceResponse.json(); |
|
|
|
const expirationDate = new Date(); |
|
expirationDate.setDate(expirationDate.getDate() + 30); |
|
document.cookie = `userId=${ |
|
userData.id |
|
};expires=${expirationDate.toUTCString()};path=/`; |
|
document.cookie = `userName=${encodeURIComponent( |
|
userName |
|
)};expires=${expirationDate.toUTCString()};path=/`; |
|
document.cookie = `userAvatar=${encodeURIComponent( |
|
avatars[avatarIndex] |
|
)};expires=${expirationDate.toUTCString()};path=/`; |
|
|
|
const joinResponse = await fetch(`/api/group/${params.inviteCode}/join`, { |
|
method: "POST", |
|
headers: { "Content-Type": "application/json" }, |
|
body: JSON.stringify({ |
|
userId: userData.id, |
|
userName, |
|
avatar: avatars[avatarIndex], |
|
}), |
|
}); |
|
|
|
if (!joinResponse.ok) |
|
throw new Error("Erreur lors de la jointure au groupe"); |
|
|
|
router.push(`/group/${params.inviteCode}`); |
|
} catch (error) { |
|
console.error("Erreur:", error); |
|
alert("Une erreur est survenue lors de la jointure au groupe"); |
|
} finally { |
|
setIsLoading(false); |
|
} |
|
}; |
|
|
|
return ( |
|
<div className="min-h-screen relative overflow-hidden"> |
|
<div className="background-pattern" /> |
|
<div className="background-overlay" /> |
|
<div className="background-vignette" /> |
|
|
|
<div className="relative z-10 p-4"> |
|
<div className="max-w-md mx-auto bg-gray-100 bg-opacity-90 backdrop-blur-sm rounded-lg shadow-xl p-8"> |
|
<div className="flex justify-between items-center mb-8"> |
|
<Link href="/"> |
|
<Button |
|
variant="outline" |
|
className="border-orange-400 text-orange-600 hover:bg-orange-100" |
|
> |
|
<ArrowLeft className="mr-2 h-4 w-4" /> |
|
Retour |
|
</Button> |
|
</Link> |
|
<h1 className="text-3xl font-grobold font-normal text-center text-orange-600"> |
|
Rejoindre la partie |
|
</h1> |
|
</div> |
|
|
|
<form onSubmit={handleSubmit} className="space-y-8"> |
|
<div className="flex flex-col items-center space-y-4"> |
|
<Avatar className="w-32 h-32 border-4 border-orange-400"> |
|
<AvatarImage src={avatars[avatarIndex]} alt="Avatar" /> |
|
<AvatarFallback>AV</AvatarFallback> |
|
</Avatar> |
|
<Button |
|
type="button" |
|
onClick={changeAvatar} |
|
variant="outline" |
|
className="border-orange-400 text-orange-600 hover:bg-orange-100" |
|
> |
|
<RefreshCcw className="mr-2 h-5 w-5" /> |
|
Changer d'avatar |
|
</Button> |
|
</div> |
|
|
|
<div className="space-y-2"> |
|
<label className="text-lg font-grobold font-normal text-orange-600"> |
|
Votre pseudo |
|
</label> |
|
<Input |
|
type="text" |
|
value={userName} |
|
onChange={(e) => setUserName(e.target.value)} |
|
className="bg-orange-50 text-orange-800 placeholder-orange-300 border-orange-200 focus:border-orange-400 focus:ring-orange-400" |
|
placeholder="Entrez votre pseudo" |
|
required |
|
/> |
|
</div> |
|
|
|
<div className="space-y-2"> |
|
<label className="text-lg font-grobold font-normal text-orange-600"> |
|
Votre voix |
|
</label> |
|
<div className="flex items-center space-x-4"> |
|
<Button |
|
type="button" |
|
onClick={isRecording ? stopRecording : startRecording} |
|
className={`flex-1 py-6 ${ |
|
isRecording |
|
? "bg-red-500 hover:bg-red-600" |
|
: "bg-orange-500 hover:bg-orange-600" |
|
} text-white`} |
|
> |
|
{isRecording ? ( |
|
<> |
|
<MicOff className="mr-2 h-5 w-5" /> |
|
Arrêter |
|
</> |
|
) : ( |
|
<> |
|
<Mic className="mr-2 h-5 w-5" /> |
|
Enregistrer |
|
</> |
|
)} |
|
</Button> |
|
</div> |
|
{audioBlob && !isRecording && ( |
|
<div className="text-green-600 font-medium text-center mt-2"> |
|
✓ Voix enregistrée |
|
</div> |
|
)} |
|
</div> |
|
|
|
<Button |
|
type="submit" |
|
disabled={isLoading || !audioBlob} |
|
className={`w-full py-6 text-lg font-grobold font-normal ${ |
|
isLoading || !audioBlob |
|
? "bg-gray-400" |
|
: "bg-green-500 hover:bg-green-600" |
|
} text-white`} |
|
> |
|
{isLoading ? "Jointure en cours..." : "Rejoindre la partie"} |
|
</Button> |
|
</form> |
|
</div> |
|
</div> |
|
</div> |
|
); |
|
} |
|
|