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: 1 addition & 1 deletion client/src/module/student/opensource/GSoCReposPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ export default function GSoCReposPage() {
</span>
<span className="h-1 w-1 bg-stone-300 dark:bg-stone-700" />
<span>
<span className="text-lime-600 dark:text-lime-400">2016-2026</span> years
<span className="text-lime-600 dark:text-lime-400">2016-{new Date().getFullYear()}</span> years
</span>
</div>
</div>
Expand Down
15 changes: 11 additions & 4 deletions client/src/module/student/opensource/ProgramTrackerPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ import {
} from "lucide-react";
import { Button } from "../../../components/ui/button";

function nextDate(month: number, day: number, hour = 23, minute = 59): string {
const now = new Date();
const d = new Date(Date.UTC(now.getFullYear(), month - 1, day, hour, minute, 0));
if (d <= now) d.setUTCFullYear(d.getUTCFullYear() + 1);
return d.toISOString();
}

// ─── Data ──────────────────────────────────────────────────────
interface Program {
id: number;
Expand Down Expand Up @@ -83,7 +90,7 @@ const PROGRAMS: Program[] = [
"Write a detailed proposal (problem statement, timeline, milestones)",
"Submit via the GSoC portal before the deadline",
],
applicationDeadline: "2026-04-19T23:59:00Z",
applicationDeadline: nextDate(4, 19),
},
{
id: 2,
Expand Down Expand Up @@ -129,7 +136,7 @@ const PROGRAMS: Program[] = [
"Complete any take-home tasks if requested",
"Wait for mentor selection notification",
],
applicationDeadline: "2026-05-15T23:59:00Z",
applicationDeadline: nextDate(5, 15),
},
{
id: 3,
Expand Down Expand Up @@ -230,8 +237,8 @@ const PROGRAMS: Program[] = [
"Make contributions to 1–2 projects during the contribution period",
"Submit a final application with your contribution summary",
],
applicationStart: "2026-02-06T16:00:00Z",
applicationDeadline: "2026-02-13T16:00:00Z",
applicationStart: nextDate(2, 6, 16, 0),
applicationDeadline: nextDate(2, 13, 16, 0),
},
{
id: 5,
Expand Down
6 changes: 5 additions & 1 deletion client/src/module/student/opensource/SuggestRepoModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,10 +276,14 @@ export function SuggestRepoModal({ open, onClose }: SuggestRepoModalProps) {
aria-invalid={!!urlError}
aria-describedby={urlError ? "suggest-url-error" : undefined}
/>
{urlError && (
{urlError ? (
<p id="suggest-url-error" className="mt-1 text-xs text-red-500">
{urlError}
</p>
) : (
<p className="mt-1 text-xs text-gray-400">
Format: https://github.com/owner/repo — we'll auto-fill the rest
</p>
)}
</div>

Expand Down
13 changes: 13 additions & 0 deletions client/src/module/student/opensource/_shared/repo-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,19 @@ export function difficultyBadge(d: OpenSourceRepo["difficulty"]) {
export function parseGithubRepoUrl(raw: string): { owner: string; name: string } | null {
const trimmed = raw.trim();
if (!trimmed) return null;

// Support SSH format: git@github.com:owner/repo.git
const sshMatch = trimmed.match(/^git@github\.com:(.+)$/);
if (sshMatch) {
const segments = sshMatch[1].split("/").filter(Boolean);
if (segments.length < 2) return null;
const [owner, rawName] = segments;
const name = rawName.replace(/\.git$/i, "");
const nameRe = /^[A-Za-z0-9._-]+$/;
if (!nameRe.test(owner) || !nameRe.test(name)) return null;
return { owner, name };
}

let url: URL;
try {
url = new URL(trimmed);
Expand Down
Loading