Skip to content

Feat/code editor - #2

Merged
R3Nexe merged 3 commits into
sky-ruler:mainfrom
R3Nexe:feat/code-editor
May 1, 2026
Merged

Feat/code editor#2
R3Nexe merged 3 commits into
sky-ruler:mainfrom
R3Nexe:feat/code-editor

Conversation

@R3Nexe

@R3Nexe R3Nexe commented May 1, 2026

Copy link
Copy Markdown
Collaborator

implemented leetcode-style code editor textbox

features

  • syntax highlighting
  • auto indentation and bracketting
  • autocomplete for python and js (currently turned off)
image

@vercel

vercel Bot commented May 1, 2026

Copy link
Copy Markdown

@R3Nexe is attempting to deploy a commit to the Sky Ruler's projects Team on Vercel.

A member of the Team first needs to authorize it.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a LeetCode-style code editor experience to the challenge details page (CodeMirror with syntax highlighting and theming), and improves local/mock development ergonomics via environment-driven mock mode and simulated delays.

Changes:

  • Replace the challenge solution textarea with a CodeMirror editor + language-specific extensions and light/dark highlighting.
  • Make mock mode configurable via VITE_USE_MOCK and add mock delays for AdminPanel mutations.
  • Enable Tailwind class-based dark mode and add editor/dev tooling dependency updates.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
client/tailwind.config.js Enables darkMode: 'class' to support Tailwind dark: variants.
client/src/pages/ChallengeDetails.jsx Integrates CodeMirror editor, adds theme syncing, and refactors submissions/details UI.
client/src/pages/AdminPanel.jsx Adds mock delays and gates write operations when USE_MOCK is enabled; minor form style tweaks.
client/src/lib/mockData.js Switches USE_MOCK to an env var and tweaks mock user shape.
client/src/lib/api.js Removes mock fallback values from normalized user fields.
client/src/context/AuthContext.jsx Removes manual refresh-if-no-token logic (relying on API interceptor refresh behavior).
client/src/App.jsx Adjusts logout flow ordering (navigate after logout).
client/package.json Adds CodeMirror-related dependencies and changes dev script behavior.
client/package-lock.json Locks new dependencies and updates transitive packages.
client/.gitignore Adds .env to ignored files.
Files not reviewed (1)
  • client/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

setRepoUrl('');
setCodeByLang({});
localStorage.removeItem(draftKey);
queryClient.invalidateQueries({ queryKey: ['my-submissions', id] });

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After a successful submission, only the ['my-submissions', id] query is invalidated now. Dashboard and profile stats queries (e.g. ['dashboard-summary'] and ['profile-stats']) will remain stale until a full refresh; consider invalidating them here as well (or updating cache via setQueryData) to keep UX consistent with the rest of the app.

Suggested change
queryClient.invalidateQueries({ queryKey: ['my-submissions', id] });
await Promise.all([
queryClient.invalidateQueries({ queryKey: ['my-submissions', id] }),
queryClient.invalidateQueries({ queryKey: ['dashboard-summary'] }),
queryClient.invalidateQueries({ queryKey: ['profile-stats'] }),
]);

Copilot uses AI. Check for mistakes.
)}
{historyQuery.data?.map((sub) => (
<Link key={sub._id} to={`/submission/${sub._id}`} className="flex items-center justify-between p-3 rounded-xl border border-white/20 hover:border-accent hover:scale-[99%] transition-all">
<div><p className={`text-sm font-semibold ${sub.status === 'Accepted' ? 'text-green-400' : 'text-red-400'}`}>{sub.status}</p><p className="text-secondary text-xs">{new Date(sub.submittedAt).toLocaleDateString()}</p></div>

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The status styling treats anything other than 'Accepted' as rejected (red). Since the app also uses 'Pending' (see mock data / admin review flow), pending submissions will be misrepresented; consider adding a distinct pending style (e.g., yellow) and preserving the previous multi-state mapping.

Suggested change
<div><p className={`text-sm font-semibold ${sub.status === 'Accepted' ? 'text-green-400' : 'text-red-400'}`}>{sub.status}</p><p className="text-secondary text-xs">{new Date(sub.submittedAt).toLocaleDateString()}</p></div>
<div><p className={`text-sm font-semibold ${sub.status === 'Accepted' ? 'text-green-400' : sub.status === 'Pending' ? 'text-yellow-400' : sub.status === 'Rejected' ? 'text-red-400' : 'text-secondary'}`}>{sub.status}</p><p className="text-secondary text-xs">{new Date(sub.submittedAt).toLocaleDateString()}</p></div>

Copilot uses AI. Check for mistakes.
Comment on lines +262 to +267
{historyQuery.data?.map((sub) => (
<Link key={sub._id} to={`/submission/${sub._id}`} className="flex items-center justify-between p-3 rounded-xl border border-white/20 hover:border-accent hover:scale-[99%] transition-all">
<div><p className={`text-sm font-semibold ${sub.status === 'Accepted' ? 'text-green-400' : 'text-red-400'}`}>{sub.status}</p><p className="text-secondary text-xs">{new Date(sub.submittedAt).toLocaleDateString()}</p></div>
<span className="text-xs bg-white/5 px-2 py-0.5 rounded text-secondary">{sub.language}</span>
</Link>
))}

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The submissions tab no longer renders any loading, error, or empty state. When historyQuery is loading or returns an empty array, this panel will be blank; consider restoring the prior skeleton/empty-state handling so users understand what's happening.

Suggested change
{historyQuery.data?.map((sub) => (
<Link key={sub._id} to={`/submission/${sub._id}`} className="flex items-center justify-between p-3 rounded-xl border border-white/20 hover:border-accent hover:scale-[99%] transition-all">
<div><p className={`text-sm font-semibold ${sub.status === 'Accepted' ? 'text-green-400' : 'text-red-400'}`}>{sub.status}</p><p className="text-secondary text-xs">{new Date(sub.submittedAt).toLocaleDateString()}</p></div>
<span className="text-xs bg-white/5 px-2 py-0.5 rounded text-secondary">{sub.language}</span>
</Link>
))}
{historyQuery.isLoading ? (
<>
<SkeletonCard />
<SkeletonCard />
<SkeletonCard />
</>
) : historyQuery.isError ? (
<div className="rounded-xl border border-red-500/20 bg-red-500/10 p-4 text-sm text-red-300">
Failed to load submissions. Please try again.
</div>
) : !historyQuery.data?.length ? (
<div className="rounded-xl border border-white/10 bg-white/5 p-4 text-sm text-secondary">
No submissions yet. Your past attempts will appear here.
</div>
) : (
historyQuery.data.map((sub) => (
<Link key={sub._id} to={`/submission/${sub._id}`} className="flex items-center justify-between p-3 rounded-xl border border-white/20 hover:border-accent hover:scale-[99%] transition-all">
<div><p className={`text-sm font-semibold ${sub.status === 'Accepted' ? 'text-green-400' : 'text-red-400'}`}>{sub.status}</p><p className="text-secondary text-xs">{new Date(sub.submittedAt).toLocaleDateString()}</p></div>
<span className="text-xs bg-white/5 px-2 py-0.5 rounded text-secondary">{sub.language}</span>
</Link>
))
)}

Copilot uses AI. Check for mistakes.
);
}
if (challengeQuery.isLoading) return <div className="grid grid-cols-1 lg:grid-cols-2 gap-4 p-8"><SkeletonCard /><SkeletonCard /></div>;
if (challengeQuery.isError || !challengeQuery.data) return <div className="p-12 text-center"><h2 className="text-xl font-bold">Not Available</h2><button className="btn-secondary mt-4" onClick={() => navigate('/dashboard')}>Back</button></div>;

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error/empty state for loading a challenge no longer displays any actionable detail (it dropped the previous error message and even the "Challenge Not Available" context). Consider showing challengeQuery.error?.userMessage (or a generic fallback) so users and developers can understand why the challenge failed to load.

Suggested change
if (challengeQuery.isError || !challengeQuery.data) return <div className="p-12 text-center"><h2 className="text-xl font-bold">Not Available</h2><button className="btn-secondary mt-4" onClick={() => navigate('/dashboard')}>Back</button></div>;
if (challengeQuery.isError || !challengeQuery.data) {
const challengeLoadMessage = challengeQuery.error?.userMessage || "We couldn't load this challenge. It may have been removed or you may not have access.";
return (
<div className="p-12 text-center">
<h2 className="text-xl font-bold">Challenge Not Available</h2>
<p className="mt-2 text-sm text-gray-400">{challengeLoadMessage}</p>
<button className="btn-secondary mt-4" onClick={() => navigate('/dashboard')}>Back</button>
</div>
);
}

Copilot uses AI. Check for mistakes.
Comment on lines +298 to 299
<button onClick={handleInsertStarter}><FiRefreshCw /></button><button onClick={handleCopyCode}><FiClipboard /></button><button onClick={handleClearDraft}><FiTrash2 /></button>
</div>

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are icon-only buttons without accessible labels. Add aria-label (and ideally type="button") so screen-reader users can understand the actions and so the buttons don't accidentally submit a parent form if this component is ever placed inside one.

Copilot uses AI. Check for mistakes.
@@ -3,11 +3,12 @@
// Set USE_MOCK to false when your backend is ready.

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header comment says “Set USE_MOCK to false when your backend is ready”, but USE_MOCK is now controlled via import.meta.env.VITE_USE_MOCK. Update this comment (and ideally document the expected .env key) so it matches the new configuration mechanism.

Suggested change
// Set USE_MOCK to false when your backend is ready.
// Controlled by the Vite env var `VITE_USE_MOCK`.
// Set `VITE_USE_MOCK=false` in your `.env` file when your backend is ready.

Copilot uses AI. Check for mistakes.
Comment thread client/package.json
"type": "module",
"scripts": {
"dev": "vite",
"dev": "BROWSER='google chrome' vite --open",

Copilot AI May 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dev script hard-codes a specific browser and uses POSIX env-var syntax, which will break on Windows shells and may not be desired in CI/other dev environments. Consider keeping vite as the default and adding an optional script (or use cross-env) for opening a browser.

Suggested change
"dev": "BROWSER='google chrome' vite --open",
"dev": "vite",
"dev:open": "vite --open",

Copilot uses AI. Check for mistakes.
@R3Nexe
R3Nexe merged commit d3e003e into sky-ruler:main May 1, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants