Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AuthProvider, useAuth } from './context/AuthContext'
import ChallengeListPage from './pages/ChallengeListPage'
import ChallengePage from './pages/ChallengePage'
import CreateChallengePage from './pages/CreateChallengePage'
import EditChallengePage from './pages/EditChallengePage'
import AboutPage from './pages/AboutPage'
import LoginPage from './pages/LoginPage'
import RegisterPage from './pages/RegisterPage'
Expand All @@ -20,6 +21,7 @@ function AppRoutes() {
<Route path="/register" element={<RegisterPage />} />
<Route path="/challenges" element={<ProtectedRoute><ChallengeListPage /></ProtectedRoute>} />
<Route path="/challenges/new" element={<ProtectedRoute><CreateChallengePage /></ProtectedRoute>} />
<Route path="/challenges/:id/edit" element={<ProtectedRoute><EditChallengePage /></ProtectedRoute>} />
<Route path="/challenges/:id" element={<ProtectedRoute><ChallengePage /></ProtectedRoute>} />
<Route path="/about" element={<AboutPage />} />
</Routes>
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/pages/ChallengeListPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export default function ChallengeListPage() {

return (
<>
<NavBar />
<div style={{ maxWidth: 800, margin: '0 auto', padding: '40px 16px' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 8 }}>
<h1 style={{ fontSize: 28, fontWeight: 700, color: '#f7fafc' }}>
Expand Down Expand Up @@ -68,6 +69,7 @@ export default function ChallengeListPage() {
<th style={{ padding: '8px 12px' }}>Title</th>
<th style={{ padding: '8px 12px' }}>Type</th>
<th style={{ padding: '8px 12px' }}>Difficulty</th>
<th style={{ padding: '8px 12px' }}>Author</th>
</tr>
</thead>
<tbody>
Expand All @@ -93,6 +95,9 @@ export default function ChallengeListPage() {
{c.difficulty}
</span>
</td>
<td style={{ padding: '12px 12px', color: '#718096', fontSize: 13 }}>
{c.createdBy ?? '—'}
</td>
</tr>
))}
</tbody>
Expand Down
54 changes: 49 additions & 5 deletions frontend/src/pages/ChallengePage.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useEffect, useRef, useState } from 'react'
import { useParams, Link } from 'react-router-dom'
import { useParams, Link, useNavigate } from 'react-router-dom'
import Editor from '@monaco-editor/react'
import api from '../api/axios'
import NavBar from '../components/NavBar'
import { useAuth } from '../context/AuthContext'

function sortKeys(val) {
if (Array.isArray(val)) return val.map(sortKeys)
Expand Down Expand Up @@ -59,6 +60,8 @@ function compareResult(challengeType, actual, expected) {

export default function ChallengePage() {
const { id } = useParams()
const navigate = useNavigate()
const { user } = useAuth()
const [challenge, setChallenge] = useState(null)
const [error, setError] = useState(null)
const [activeSchema, setActiveSchema] = useState(0)
Expand Down Expand Up @@ -166,11 +169,52 @@ export default function ChallengePage() {
</span>
</div>

<h1 style={{ fontSize: 22, fontWeight: 700, marginTop: 12, marginBottom: 16, color: '#f7fafc' }}>
{challenge.title}
</h1>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginTop: 12, marginBottom: 4 }}>
<h1 style={{ fontSize: 22, fontWeight: 700, color: '#f7fafc', margin: 0 }}>
{challenge.title}
</h1>
{(user?.username === challenge.createdBy || user?.role === 'ADMIN') && (
<div style={{ display: 'flex', gap: 8, flexShrink: 0, marginLeft: 16 }}>
<Link
to={`/challenges/${id}/edit`}
style={{
fontSize: 13,
color: '#f7fafc',
background: '#2d3748',
border: '1px solid #4a5568',
padding: '4px 12px',
borderRadius: 5,
textDecoration: 'none',
}}
>
Edit
</Link>
<button
onClick={async () => {
if (!confirm('Delete this challenge?')) return
await api.delete(`/challenges/${id}`)
navigate('/challenges')
}}
style={{
fontSize: 13,
color: '#fc8181',
background: 'none',
border: '1px solid #822727',
padding: '4px 12px',
borderRadius: 5,
cursor: 'pointer',
}}
>
Delete
</button>
</div>
)}
</div>
{challenge.createdBy && (
<p style={{ fontSize: 12, color: '#4a5568', marginBottom: 12 }}>by {challenge.createdBy}</p>
)}

<p style={{ color: '#a0aec0', lineHeight: 1.7, marginBottom: 28 }}>
<p style={{ color: '#a0aec0', lineHeight: 1.7, marginTop: 12, marginBottom: 28 }}>
{challenge.description}
</p>

Expand Down
Loading
Loading