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
Some checks failed
platform/bro-js/challenge-pl/pipeline/head There was a failure building this commit
This commit is contained in:
@@ -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 />
|
||||
|
||||
Reference in New Issue
Block a user