fix: QA report bugs BUG-01 through BUG-11 resolved - streak modal close btn, calculator crash guard, AI chat auto-scroll, leaderboard zero-streak fix, name annotation cleanup everywhere, CBT score display colors, PrepPilot difficulty badge layout
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import { useState } from "react"
|
||||
import { useState, useRef, useEffect } from "react"
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Input } from "@/components/ui/input"
|
||||
@@ -39,6 +39,15 @@ export function AITutorChat() {
|
||||
const [input, setInput] = useState('');
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
// BUG-03 fix: ref to anchor bottom of chat for auto-scroll
|
||||
const bottomRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Auto-scroll to latest message whenever messages change
|
||||
useEffect(() => {
|
||||
if (bottomRef.current) {
|
||||
bottomRef.current.scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}, [messages]);
|
||||
|
||||
const handleSend = () => {
|
||||
if (!input.trim()) return;
|
||||
@@ -118,6 +127,8 @@ export function AITutorChat() {
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{/* BUG-03 fix: invisible scroll anchor */}
|
||||
<div ref={bottomRef} />
|
||||
</CardContent>
|
||||
|
||||
<CardFooter className="p-4 border-t border-border bg-background shrink-0">
|
||||
|
||||
@@ -20,8 +20,17 @@ export function Calculator({ isOpen, onClose }: CalculatorProps) {
|
||||
|
||||
const handleCalculate = () => {
|
||||
try {
|
||||
if (!display.trim()) return;
|
||||
|
||||
// BUG-02 fix: strip trailing operator(s) so "5*", "9+", "/2" (leading slash) don't crash
|
||||
const sanitized = display
|
||||
.replace(/[+\-*/^]+$/, "") // remove trailing operators
|
||||
.replace(/^[*/^]+/, ""); // remove leading * / ^ (but allow leading minus for negatives)
|
||||
|
||||
if (!sanitized.trim()) return;
|
||||
|
||||
// Map functions to JS Math
|
||||
let mappedExp = display
|
||||
let mappedExp = sanitized
|
||||
.replace(/sin\(/g, 'Math.sin(')
|
||||
.replace(/cos\(/g, 'Math.cos(')
|
||||
.replace(/tan\(/g, 'Math.tan(')
|
||||
@@ -30,8 +39,15 @@ export function Calculator({ isOpen, onClose }: CalculatorProps) {
|
||||
.replace(/sqrt\(/g, 'Math.sqrt(')
|
||||
.replace(/\^/g, '**');
|
||||
|
||||
// eslint-disable-next-line no-new-func
|
||||
const result = new Function('return ' + mappedExp)();
|
||||
|
||||
// Guard against NaN / Infinity
|
||||
if (result === null || result === undefined || !isFinite(result) || isNaN(result)) {
|
||||
setDisplay("Error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle floating point precision issues simply
|
||||
if (typeof result === 'number' && !Number.isInteger(result)) {
|
||||
setDisplay(String(parseFloat(result.toFixed(6))));
|
||||
@@ -43,6 +59,7 @@ export function Calculator({ isOpen, onClose }: CalculatorProps) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleClear = () => setDisplay("");
|
||||
const handleBackspace = () => setDisplay((prev) => prev.slice(0, -1));
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Flame, Sparkles } from "lucide-react";
|
||||
import { Flame, Sparkles, X } from "lucide-react";
|
||||
import { useActiveUser } from "@/hooks/useActiveUser";
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
@@ -42,7 +42,7 @@ export function StreakOnboardingModal() {
|
||||
wishMessage = `Incredible! A ${streak}-day streak shows true championship discipline. You are outperforming the competition. Let's make today count!`;
|
||||
}
|
||||
|
||||
const handleEnter = () => {
|
||||
const handleDismiss = () => {
|
||||
sessionStorage.setItem(`hasSeenStreakPopup_${user.id}`, "true");
|
||||
setIsOpen(false);
|
||||
};
|
||||
@@ -57,10 +57,24 @@ export function StreakOnboardingModal() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-background/85 backdrop-blur-md animate-in fade-in duration-300">
|
||||
|
||||
{/* Centered Modal Card Container covering 80% screen size (w-[80vw] h-[80vh]) */}
|
||||
<div className="bg-background border-none shadow-[0_0_60px_-10px_rgba(0,240,255,0.25)] rounded-3xl w-[80vw] max-w-5xl h-[80vh] max-h-[800px] relative overflow-hidden animate-in zoom-in-95 slide-in-from-bottom-4 duration-300 z-20 pointer-events-auto mx-4 flex flex-col justify-start">
|
||||
// BUG-01 fix: backdrop click dismisses modal
|
||||
<div
|
||||
className="fixed inset-0 z-50 flex items-center justify-center bg-black/70 backdrop-blur-md animate-in fade-in duration-300"
|
||||
onClick={handleDismiss}
|
||||
>
|
||||
{/* Centered Modal Card — stop propagation so inner clicks don't close */}
|
||||
<div
|
||||
className="bg-background border border-border shadow-[0_0_60px_-10px_rgba(0,240,255,0.25)] rounded-3xl w-[90vw] max-w-5xl h-[85vh] max-h-[800px] relative overflow-hidden animate-in zoom-in-95 slide-in-from-bottom-4 duration-300 z-20 pointer-events-auto mx-4 flex flex-col justify-start"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* BUG-01 fix: X close button */}
|
||||
<button
|
||||
onClick={handleDismiss}
|
||||
className="absolute top-4 right-4 z-30 size-9 flex items-center justify-center rounded-full bg-background/80 border border-border text-muted-foreground hover:text-foreground hover:bg-secondary transition-all duration-200 shadow-sm"
|
||||
aria-label="Close streak modal"
|
||||
>
|
||||
<X size={18} />
|
||||
</button>
|
||||
|
||||
{/* Subtle background glow */}
|
||||
<div className="absolute -right-20 -top-20 size-48 bg-[#00F0FF]/5 rounded-full blur-3xl pointer-events-none" />
|
||||
@@ -112,7 +126,7 @@ export function StreakOnboardingModal() {
|
||||
{/* Action Button */}
|
||||
<div className="pt-2 max-w-sm w-full mx-auto">
|
||||
<Button
|
||||
onClick={handleEnter}
|
||||
onClick={handleDismiss}
|
||||
className="w-full h-12 rounded-xl text-base font-black bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 shadow-[0_0_15px_-3px_#00F0FF] hover:shadow-[0_0_25px_#00F0FF] hover:-translate-y-0.5 transition-all duration-300"
|
||||
>
|
||||
Enter Workspace
|
||||
|
||||
Reference in New Issue
Block a user