Implement completion screen in MainPage component to celebrate task achievements. Introduce state management for completed chains and enhance UI with congratulatory messages and a continue button. Remove unused notification logic to streamline the component.
Some checks failed
platform/bro-js/challenge-pl/pipeline/head There was a failure building this commit

This commit is contained in:
2025-12-13 19:27:25 +03:00
parent 259b1c9353
commit f774cd27d8

View File

@@ -1,7 +1,10 @@
import React, { useEffect, useRef, useState } from 'react'
import {
Box,
Button,
Heading,
Text,
VStack,
} from '@chakra-ui/react'
import { Alert } from '@chakra-ui/react/alert'
@@ -16,14 +19,13 @@ const SELECTED_CHAIN_KEY = 'challengeSelectedChainId'
const SELECTED_TASK_KEY = 'challengeSelectedTaskId'
export const MainPage = () => {
const { nickname, eventEmitter, chains } = useChallenge()
const { nickname, chains } = useChallenge()
const [selectedChain, setSelectedChain] = useState<ChallengeChain | null>(null)
const [selectedTask, setSelectedTask] = useState<ChallengeTask | null>(null)
const [completedChainName, setCompletedChainName] = useState<string | null>(null)
const [isOffline, setIsOffline] = useState(() =>
typeof navigator !== 'undefined' ? !navigator.onLine : false,
)
const [notification, setNotification] = useState<{ status: 'success' | 'warning'; title: string; description?: string } | null>(null)
const notificationTimeoutRef = useRef<number | null>(null)
const hasRestoredState = useRef(false)
// Восстановление состояния при загрузке
@@ -66,7 +68,8 @@ export const MainPage = () => {
setSelectedTask(nextTask)
localStorage.setItem(SELECTED_TASK_KEY, nextTask.id)
} else {
// Цепочка завершена, возвращаемся к выбору
// Цепочка завершена - показываем экран поздравления
setCompletedChainName(selectedChain.name)
setSelectedChain(null)
setSelectedTask(null)
localStorage.removeItem(SELECTED_CHAIN_KEY)
@@ -74,33 +77,10 @@ export const MainPage = () => {
}
}
useEffect(() => {
const unsubscribe = eventEmitter.on('submission_completed', (event) => {
const submission = (event.data as { submission?: { status: string; attemptNumber: number } })?.submission
const accepted = submission?.status === 'accepted'
const handleContinueAfterCompletion = () => {
setCompletedChainName(null)
}
if (!accepted) {
return
}
const title = 'Задание принято'
const description = submission ? `Попытка №${submission.attemptNumber}` : undefined
if (notificationTimeoutRef.current) {
window.clearTimeout(notificationTimeoutRef.current)
}
// setNotification({ status: 'success', title, description })
notificationTimeoutRef.current = window.setTimeout(() => setNotification(null), 4000)
})
return () => {
unsubscribe()
if (notificationTimeoutRef.current) {
window.clearTimeout(notificationTimeoutRef.current)
}
}
}, [eventEmitter])
useEffect(() => {
const handleOnline = () => setIsOffline(false)
@@ -120,6 +100,61 @@ export const MainPage = () => {
return <LoginForm />
}
// Если цепочка завершена, показываем экран поздравления
if (completedChainName) {
return (
<>
<Header />
<Box bg="gray.50" minH="100vh" display="flex" alignItems="center" justifyContent="center" px={4}>
<Box
bg="white"
borderWidth="2px"
borderRadius="xl"
borderColor="green.300"
p={10}
maxW="600px"
w="full"
textAlign="center"
shadow="lg"
>
<VStack gap={6}>
<Text fontSize="6xl">🎉</Text>
<Heading size="xl" color="green.600">
Поздравляем!
</Heading>
<Text fontSize="lg" color="gray.700">
Вы успешно выполнили все задания
</Text>
<Box
bg="green.50"
borderRadius="lg"
px={6}
py={3}
borderWidth="1px"
borderColor="green.200"
>
<Text fontSize="xl" fontWeight="bold" color="green.700">
{completedChainName}
</Text>
</Box>
<Text fontSize="md" color="gray.600">
Отличная работа! Вы можете продолжить обучение, выбрав другую цепочку заданий.
</Text>
<Button
colorScheme="green"
size="lg"
onClick={handleContinueAfterCompletion}
mt={4}
>
Продолжить
</Button>
</VStack>
</Box>
</Box>
</>
)
}
// Если цепочка не выбрана, показываем селектор цепочек
if (!selectedChain) {
return (
@@ -138,16 +173,6 @@ export const MainPage = () => {
<Header chainName={selectedChain.name} taskProgress={taskProgress} />
<Box bg="gray.50" minH="100vh" py={4} px={{ base: 4, md: 8 }}>
<Box maxW="1200px" mx="auto">
{notification && (
<Alert.Root status={notification.status} borderRadius="md" mb={4}>
<Alert.Indicator />
<Box ml={3}>
<Text fontWeight="semibold">{notification.title}</Text>
{notification.description && <Text fontSize="sm">{notification.description}</Text>}
</Box>
</Alert.Root>
)}
{isOffline && (
<Alert.Root status="warning" borderRadius="md" mb={4}>
<Alert.Indicator />