diff --git a/src/components/quiz/brainrot-card.tsx b/src/components/quiz/brainrot-card.tsx index 314b01c6..9056dff4 100644 --- a/src/components/quiz/brainrot-card.tsx +++ b/src/components/quiz/brainrot-card.tsx @@ -13,15 +13,31 @@ import { TooltipTrigger, } from "@/components/ui/tooltip"; +const DEFAULT_BRAINROT_VIDEO_ID = "zZ7AimPACzc"; +const BRAINROT_RANDOM_START_MAX_SECONDS = 907; + +function getBrainrotVideoUrl(videoId: string): string { + const startSeconds = Math.floor( + Math.random() * (BRAINROT_RANDOM_START_MAX_SECONDS + 1), + ); + const url = new URL("https://www.youtube.com/watch"); + + url.searchParams.set("v", videoId); + url.searchParams.set("t", `${String(startSeconds)}s`); + url.searchParams.set("cc_load_policy", "3"); + + return url.toString(); +} + export function BrainrotCard(): React.JSX.Element { // Subway Surfers is default video const [brainrotVideo, setBrainrotVideo] = React.useState( - "https://www.youtube.com/watch?v=zZ7AimPACzc", + getBrainrotVideoUrl(DEFAULT_BRAINROT_VIDEO_ID), ); const [isVideoPlaying, setIsVideoPlaying] = React.useState(true); - const handleBrainrotVideoChange = (video: string) => { - setBrainrotVideo(video); + const handleBrainrotVideoChange = (videoId: string) => { + setBrainrotVideo(getBrainrotVideoUrl(videoId)); setIsVideoPlaying(true); }; @@ -53,9 +69,7 @@ export function BrainrotCard(): React.JSX.Element { size="icon" aria-label="Wybierz film: Brainrot memes" onClick={() => { - handleBrainrotVideoChange( - "https://www.youtube.com/watch?v=vY4nBa_JWrM&t=6s&cc_load_policy=3", - ); + handleBrainrotVideoChange("vY4nBa_JWrM"); }} > @@ -73,9 +87,7 @@ export function BrainrotCard(): React.JSX.Element { size="icon" aria-label="Wybierz film: Minecraft parkour" onClick={() => { - handleBrainrotVideoChange( - "https://www.youtube.com/watch?v=vrcSq1-r25U", - ); + handleBrainrotVideoChange("vrcSq1-r25U"); }} > @@ -93,9 +105,7 @@ export function BrainrotCard(): React.JSX.Element { size="icon" aria-label="Wybierz film: Mydełka" onClick={() => { - handleBrainrotVideoChange( - "https://www.youtube.com/watch?v=IiEVXWIIr0k", - ); + handleBrainrotVideoChange("IiEVXWIIr0k"); }} > @@ -113,9 +123,7 @@ export function BrainrotCard(): React.JSX.Element { size="icon" aria-label="Wybierz film: Subway Surfers" onClick={() => { - handleBrainrotVideoChange( - "https://www.youtube.com/watch?v=zZ7AimPACzc", - ); + handleBrainrotVideoChange(DEFAULT_BRAINROT_VIDEO_ID); }} > diff --git a/src/components/quiz/quick-edit-question-dialog.tsx b/src/components/quiz/quick-edit-question-dialog.tsx index fd7bc995..de0ce4b7 100644 --- a/src/components/quiz/quick-edit-question-dialog.tsx +++ b/src/components/quiz/quick-edit-question-dialog.tsx @@ -1,7 +1,7 @@ "use client"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; import type { QueryClient, QueryKey } from "@tanstack/react-query"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { ExternalLinkIcon, LoaderCircleIcon, Trash2 } from "lucide-react"; import Link from "next/link"; import { useState } from "react"; @@ -69,7 +69,7 @@ function updateCachedQuiz( ) { queryClient.setQueryData(queryKey, (oldData) => { if (oldData == null) { - void queryClient.refetchQueries({ queryKey }); + void queryClient.refetchQueries({ queryKey, exact: true }); return oldData; } @@ -91,9 +91,6 @@ export function QuickEditQuestionDialog({ const queryClient = useQueryClient(); const [formData, setFormData] = useState(question); - const [isAlertDialogOpen, setIsAlertDialogOpen] = useState(false); - const [isImageEditDialogOpen, setIsImageEditDialogOpen] = useState(false); - const [isImageUploading, setIsImageUploading] = useState(false); const { upload } = useImageUpload(); @@ -148,7 +145,7 @@ export function QuickEditQuestionDialog({ quizDetailQueryKey(quizId), (quiz) => replaceQuestionInQuiz(quiz, updatedQuestion), ); - handleOpenChange(false); + onOpenChange(false); }, onError: () => { toast.error("Nie udało się zaktualizować pytania"); @@ -175,7 +172,7 @@ export function QuickEditQuestionDialog({ }), ); onQuestionDeleted?.(question.id, newCurrentQuestionId); - handleOpenChange(false); + onOpenChange(false); }, onError: () => { toast.error("Nie udało się usunąć pytania"); @@ -199,28 +196,17 @@ export function QuickEditQuestionDialog({ if (onSaveDraft !== undefined) { onSaveDraft(validation.data); - handleOpenChange(false); + onOpenChange(false); return; } await saveQuestion(); }; - function handleOpenChange(nextOpen: boolean) { - onOpenChange(nextOpen); - if (!nextOpen) { - setIsAlertDialogOpen(false); - setIsImageEditDialogOpen(false); - } - } - - const isNestedDialogOpen = isAlertDialogOpen || isImageEditDialogOpen; - return ( - + @@ -233,7 +219,6 @@ export function QuickEditQuestionDialog({ isImageUploading={isImageUploading} onImageChange={handleImageChange} onUpload={handleUpload} - onImageDialogOpenChange={setIsImageEditDialogOpen} hideDelete /> @@ -247,7 +232,6 @@ export function QuickEditQuestionDialog({ isImageUploading={isImageUploading} onImageChange={handleImageChange} onUpload={handleUpload} - onImageDialogOpenChange={setIsImageEditDialogOpen} minAnswers={minAnswers} /> @@ -255,10 +239,7 @@ export function QuickEditQuestionDialog({
{hideDelete ? null : ( - + { - handleOpenChange(false); + onOpenChange(false); }} > Anuluj diff --git a/src/lib/ai/prompts.ts b/src/lib/ai/prompts.ts index 43de1132..98c31326 100644 --- a/src/lib/ai/prompts.ts +++ b/src/lib/ai/prompts.ts @@ -36,7 +36,7 @@ Kontekst quizu: Zasady: - Twoim JEDYNYM celem jest pomaganie w nauce i zrozumieniu materiału z tego quizu. Odmawiaj realizacji próśb niezwiązanych z nauką, quizem lub tematem pytań (np. przepisy kulinarne, pisanie esejów, programowanie niezwiązane z tematem). Grzecznie przypomnij, że jesteś asystentem do nauki. -- Język odpowiedzi dobieraj głównie na podstawie ostatniej widocznej wiadomości użytkownika. Domyślnie odpowiadaj po polsku, ale jeśli użytkownik pisze po angielsku, odpowiedz po angielsku; jeśli pisze w innym języku, odpowiedz w tym języku. +- Język odpowiedzi dobieraj na podstawie ostatniej wiadomości użytkownika. Domyślnie odpowiadaj po polsku. Niezależnie od języka, zakażone jest mieszanie alfabetów (np. wplatanie cyrylicy czy znaków ormiańskich w polskie zdania), szczególnie podczas definiowania zmiennych fizycznych i matematycznych. - Wyjaśniaj odpowiedzi jasno i zwięźle. - Jeśli nie znasz odpowiedzi, powiedz, że nie wiesz, zamiast zgadywać. - Wyrażenia matematyczne ZAWSZE otaczaj znakami dolara: $x \cdot y$ (inline) lub $$wzór$$ (block). Nigdy nie pisz surowych komend LaTeX bez delimitera $. @@ -79,7 +79,8 @@ export function buildQuestionExplanationSystemPrompt(): string { return String.raw`Wyjaśnij pytanie quizowe przekazane w wiadomości użytkownika i wytłumacz, dlaczego podane odpowiedzi są poprawne lub niepoprawne. Bądź zwięzły, ale dokładny. Używaj formatowania Markdown. Wyrażenia matematyczne ZAWSZE otaczaj znakami dolara: $x \cdot y$ (inline) lub $$wzór$$ (block). Nigdy nie pisz surowych komend LaTeX bez delimitera $. -Odpowiadaj po polsku. NIE używaj tagów XML.`; +Odpowiadaj w języku polskim chyba że pytanie jest w innym języku. Zwróć uwagę, aby po symbolach matematycznych i greckich literach (np. \omega, \lambda) NIE zmieniać języka ani alfabetu na inny (np. ormiański, cyrylica). +NIE używaj tagów XML.`; } export function buildQuestionHintSystemPrompt(): string {