Repository navigation
Conversation
…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
|
@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. |
👷 Deploy request for staging-mulearn pending review.Visit the deploys page to approve it
|
[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
SummaryAdds public problem-statement browsing and learner submissions, plus company/admin tools to create, edit, publish, and review challenges.
|
| ======= | ||
| {/* Admin notice: authored directly for muLearn */} | ||
| {isAdmin && !isEditing && ( |
There was a problem hiding this comment.
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!
| 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]); |
There was a problem hiding this comment.
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.
| 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) }, | ||
| ); |
There was a problem hiding this comment.
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.
| onSuccess: async (_data, { id }) => { | ||
| await queryClient.invalidateQueries({ | ||
| queryKey: problemStatementKeys.companyDetail(id), | ||
| }); | ||
| await queryClient.invalidateQueries({ | ||
| queryKey: problemStatementKeys.companyLists(), | ||
| }); |
There was a problem hiding this comment.
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.
| <Button | ||
| size="sm" | ||
| variant="outline" | ||
| className="rounded-xl text-xs gap-1.5 pointer-events-none" | ||
| > |
There was a problem hiding this comment.
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.
| 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)); |
There was a problem hiding this comment.
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.
| const client = authenticated ? apiClient : publicApiClient; | ||
| return client.get<PaginatedResponse<ProblemStatement>>(url); |
There was a problem hiding this comment.
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"; |
There was a problem hiding this comment.
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"> |
There was a problem hiding this comment.
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!
| {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> |
There was a problem hiding this comment.
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.
https://mulearn-dashboard-three.vercel.app/