Skip to content

Implement problem statement feature - #528

Draft
erzer12 wants to merge 2 commits into
gtech-mulearn:devfrom
erzer12:dev
Draft

erzer12 wants to merge 2 commits into
gtech-mulearn:devfrom
erzer12:dev

Conversation

@erzer12

@erzer12 erzer12 commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

…bmissions and interaction lifecycle

- Add real backend endpoints for solution submission (PUT) and withdrawal (DELETE)
- Replace mock Zustand submission store with TanStack Query mutations (`useSubmitSolution`, `useWithdrawSubmission`)
- Add strict submission URL validation schema (HTTPS, valid TLD domain, no localhost/IP/credentials, max 500 chars)
- Support 3-state learner interaction flow (unregistered -> Trying -> Submitted) with deadline guards
- Add interaction breakdown counters (`trying_count`, `submitted_count`) across cards, tables, and detail views
- Support `source` ('company' | 'mulearn') and `status` query filters on feed and management rosters
- Update management detail view with interaction status tabs, raw URL link displays, and admin single-learner interaction deletion
@vercel

vercel Bot commented Oct 18, 2026

Copy link
Copy Markdown

@erzer12 is attempting to deploy a commit to the awindsr's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-project-automation github-project-automation Bot moved this to Backlog in µlearn 5.0 Oct 18, 2026
@netlify

netlify Bot commented Oct 18, 2026

Copy link
Copy Markdown

👷 Deploy request for staging-mulearn pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 446443c

@greptile-apps

greptile-apps Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 1/5

[Medium impact] The new workflow reaches learners, company users, and platform admins.

The PR needs fixes before merging because its create/edit form is duplicated, participant lists miss records, and management changes leave public pages stale.

Findings

  1. P1 Every field appears twice ▶
  2. P1 Personal tabs miss joined challenges ▶
  3. P1 Later submissions cannot be reviewed ▶
  4. P1 Public pages keep old details ▶
  5. P2 Keyboard cannot open table rows ▶
  6. P2 Failed edits show duplicate errors ▶
  7. P2 Feed failures look empty ▶
  8. P2 Old drafts survive new opens ▶
  9. P2 Other companies see management links ▶
  10. P2 Response checks are skipped ▶
  11. P2 Imports depend on auth internals ▶
  12. P2 Tables bypass shared behavior ▶
  13. P2 Mobile offers locked submission edits ▶

Summary

Adds public problem-statement browsing and learner submissions, plus company/admin tools to create, edit, publish, and review challenges.

  • Learners can browse published problem statements and take part in challenges.
  • Company users and admins can create and manage problem statements.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Public[Public feed and detail] --> PublicHooks[Feed and interaction hooks]
  PublicHooks --> PublicAPI[Public or authenticated gateway]
  Learner[Learner] --> Submit[Join or submit solution]
  Submit --> PublicHooks
  Owner[Company owner or admin] --> Manage[Management pages]
  Manage --> ManageHooks[Company or admin hooks]
  ManageHooks --> PrivateAPI[Authenticated gateway]
  ManageHooks --> ManagementCache[Refresh management cache]
  PublicHooks --> PublicCache[Public feed and detail cache]
Loading

Reviews (1) · Last reviewed commit: "feat(problem-statements): align with upd..." · Reviewed by Greptile

Comment on lines +472 to +474
=======
{/* Admin notice: authored directly for muLearn */}
{isAdmin && !isEditing && (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Every field appears twice

The create/edit dialog renders two copies of every field, separated by a literal =======. Both copies register the same field names and reuse the same HTML IDs, so users see competing inputs for the same values. Remove the separator and duplicate field block.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +68 to +76
const statements = useMemo(() => {
if (statusFilter === "trying") {
return rawStatements.filter((s) => s.my_interaction === "Trying");
}
if (statusFilter === "submitted") {
return rawStatements.filter((s) => s.my_interaction === "Submitted");
}
return rawStatements;
}, [rawStatements, statusFilter]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Personal tabs miss joined challenges

The “I'm Trying” and “Submitted” tabs filter only the current 12-item feed page. When a learner's matching challenges are on later pages, the first page incorrectly says they have not tried any challenges. The page buttons and totals still describe the unfiltered feed. Filter the full matching set before paging and use totals for that set.

Comment on lines +138 to +147
const companyInteractionsQuery = useCompanyInteractions(
statementId,
{ pageIndex: 1, perPage: 100 },
{ enabled: Boolean(userInfo && !isAdmin && isCompany) },
);
const adminInteractionsQuery = useAdminInteractions(
statementId,
{ pageIndex: 1, perPage: 100 },
{ enabled: Boolean(userInfo && isAdmin) },
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Later submissions cannot be reviewed

Both management roster requests always fetch page 1 with perPage: 100. Search and status filters run only on those rows, and there are no controls to fetch later pages. Once a challenge has more than 100 participants, owners cannot find or review the remaining submissions. Use the endpoint's search, status, and page parameters.

Comment on lines +290 to +296
onSuccess: async (_data, { id }) => {
await queryClient.invalidateQueries({
queryKey: problemStatementKeys.companyDetail(id),
});
await queryClient.invalidateQueries({
queryKey: problemStatementKeys.companyLists(),
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Public pages keep old details

Management mutations refresh only the company or admin cache, not the separate public feed and detail caches. An owner can browse a challenge, edit or unpublish it in management, then return within the 60-second freshness window and still see its old content and actions. Refresh the affected public keys after updates, deletes, and publish changes too.

Comment on lines +202 to +206
<Button
size="sm"
variant="outline"
className="rounded-xl text-xs gap-1.5 pointer-events-none"
>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Keyboard cannot open table rows

The View button has no click handler. Opening a challenge depends entirely on the mouse click attached to the surrounding <tr>, so keyboard users can focus View but pressing Enter or Space does nothing. Put onView(statement) on the button instead of relying on the row.

Comment on lines +131 to +140
const companyInteractionsQuery = useCompanyInteractions(
statementId,
{ pageIndex: 1, perPage: 50 },
{ enabled: Boolean(userInfo && !isAdmin && isCompany && statement?.id) },
);
const interactionsQuery = isAdmin
? adminInteractionsQuery
: companyInteractionsQuery;
const interactions = interactionsQuery.data?.data ?? [];
const canManage = isAdmin || (isCompany && Boolean(statement?.company?.id));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Other companies see management links

canManage checks only whether the statement has a company ID, and the roster request has no ownership check either. A company user viewing another company's public challenge sees management links that lead to a not-found page. Compare the statement's company with the signed-in user's company before showing these controls or fetching its private roster.

Comment on lines +42 to +43
const client = authenticated ? apiClient : publicApiClient;
return client.get<PaginatedResponse<ProblemStatement>>(url);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Response checks are skipped

The new API functions never pass their Zod response schemas to the gateway. Type arguments alone do not check received data, so unexpected responses reach the pages without shape checks or mismatch logs. The repository requires these schemas; add envelope-aware schemas and unwrap their parsed responses consistently across the three API files before merging.

import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
import { StateDisplay } from "@/components/ui/state-display";
import { useUserInfo } from "@/features/auth/hooks";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Imports depend on auth internals

The new feature imports useUserInfo from @/features/auth/hooks, bypassing the auth feature's public barrel. This ties callers to its internal file layout. The repository requires cross-feature imports through @/features/<feature>; use @/features/auth here and at the other new call sites before merging.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

return (
<div className="overflow-hidden rounded-2xl border border-border bg-card shadow-xs">
<div className="overflow-x-auto">
<table className="w-full text-left text-sm">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Tables bypass shared behavior

The feature adds three hand-written list tables instead of using the shared Table. This creates separate row actions, empty states, and table behavior to maintain. The repository requires list views to use Table and its paired controls; reuse them here, in the management roster, and in the public detail roster before merging.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +818 to +825
{isSubmitted ? (
<Button
size="sm"
onClick={() => setShowSubmitDialog(true)}
className="shrink-0 rounded-full px-5 py-2 text-xs font-semibold bg-emerald-600 hover:bg-emerald-700 text-white"
>
Update Link
</Button>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Mobile offers locked submission edits

On mobile, a submitted challenge always shows an enabled Update Link button, even after its deadline. The desktop controls check isOpen, and the submission API only allows changes before the deadline. Apply the same check here so users do not open a form whose save will be rejected.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage
Status: Backlog

Development

Successfully merging this pull request may close these issues.

2 participants