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
15 changes: 15 additions & 0 deletions app/admin/dsoc/projects/[id]/edit/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export default function EditProjectPage() {
organization: '',
repositoryUrl: '',
websiteUrl: '',
timelineUrl: '',
difficulty: 'intermediate',
duration: '3 months',
technologies: '',
Expand Down Expand Up @@ -104,6 +105,7 @@ export default function EditProjectPage() {
organization: project.organization || '',
repositoryUrl: project.repositoryUrl || '',
websiteUrl: project.websiteUrl || '',
timelineUrl: project.timelineUrl || '',
difficulty: project.difficulty || 'intermediate',
duration: project.duration || '3 months',
technologies: Array.isArray(project.technologies) ? project.technologies.join(', ') : '',
Expand Down Expand Up @@ -221,6 +223,7 @@ export default function EditProjectPage() {
organization: formData.organization,
repositoryUrl: formData.repositoryUrl,
websiteUrl: formData.websiteUrl,
timelineUrl: formData.timelineUrl,
difficulty: formData.difficulty,
duration: formData.duration,
technologies: formData.technologies.split(',').map(s => s.trim()).filter(Boolean),
Expand Down Expand Up @@ -630,6 +633,18 @@ export default function EditProjectPage() {
placeholder="e.g., 2025, Summer 2025"
/>
</div>

<div>
<label className="block font-bold text-sm mb-2">Timeline Link</label>
<input
type="url"
name="timelineUrl"
value={formData.timelineUrl}
onChange={handleChange}
className="neo-brutal-input"
placeholder="https://example.com/timeline"
/>
</div>
</div>

{/* Requirements */}
Expand Down
13 changes: 13 additions & 0 deletions app/admin/dsoc/projects/new/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export default function NewProjectPage() {
organization: '',
repositoryUrl: '',
websiteUrl: '',
timelineUrl: '',
difficulty: 'intermediate',
duration: '3 months',
technologies: '',
Expand Down Expand Up @@ -541,6 +542,18 @@ export default function NewProjectPage() {
placeholder="e.g., 2025, Summer 2025"
/>
</div>

<div>
<label className="block font-bold text-sm mb-2">Timeline Link</label>
<input
type="url"
name="timelineUrl"
value={formData.timelineUrl}
onChange={handleChange}
className="neo-brutal-input"
placeholder="https://example.com/timeline"
/>
</div>
</div>

{/* Requirements */}
Expand Down
14 changes: 12 additions & 2 deletions app/api/dsoc/applications/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ async function getMenteeFromToken(request: NextRequest) {
}
}

function getDeadlineEnd(dateString: string) {
const [year, month, day] = dateString.split('-').map(Number);

if (!year || !month || !day) {
return new Date(dateString);
}

return new Date(year, month - 1, day, 23, 59, 59, 999);
}

// Helper to get mentor from token
async function getMentorFromToken(request: NextRequest) {
const token = request.cookies.get('dsoc-mentor-token')?.value;
Expand Down Expand Up @@ -59,7 +69,7 @@ export async function GET(request: NextRequest) {
.select('_id')
.lean();

const mentorProjectIds = mentorProjects.map((project) => project._id.toString());
const mentorProjectIds = mentorProjects.map((project) => String(project._id));

if (projectId) {
if (!mentorProjectIds.includes(projectId)) {
Expand Down Expand Up @@ -129,7 +139,7 @@ export async function POST(request: NextRequest) {
);
}

if (new Date() > new Date(project.applicationDeadline)) {
if (new Date() > getDeadlineEnd(project.applicationDeadline)) {
return NextResponse.json(
{ success: false, error: 'Application deadline has passed' },
{ status: 400 }
Expand Down
1 change: 1 addition & 0 deletions app/dsoc/apply/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
<option value="UTC-05:00">UTC-05:00 (Eastern Time)</option>
<option value="UTC+00:00">UTC+00:00 (London)</option>
<option value="UTC+01:00">UTC+01:00 (Central Europe)</option>
<option value="UTC+05:00">UTC+05:00 (Pakistan)</option>
<option value="UTC+05:30">UTC+05:30 (India)</option>
<option value="UTC+08:00">UTC+08:00 (Singapore/China)</option>
<option value="UTC+09:00">UTC+09:00 (Japan/Korea)</option>
Expand Down
51 changes: 50 additions & 1 deletion app/dsoc/projects/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ interface Project {
organization: string;
repositoryUrl: string;
websiteUrl?: string;
timelineUrl?: string;
difficulty: 'beginner' | 'intermediate' | 'advanced';
duration: string;
technologies: string[];
Expand Down Expand Up @@ -367,7 +368,17 @@ export default function ProjectDetailPage({ params }: { params: Promise<{ id: st
});
};

const isDeadlinePassed = project ? new Date() >= new Date(project.applicationDeadline) : false;
const getDeadlineEnd = (dateString: string) => {
const [year, month, day] = dateString.split('-').map(Number);

if (!year || !month || !day) {
return new Date(dateString);
}

return new Date(year, month - 1, day, 23, 59, 59, 999);
};

const isDeadlinePassed = project ? new Date() > getDeadlineEnd(project.applicationDeadline) : false;
const spotsRemaining = project ? project.maxMentees - (project.selectedMentees?.length || 0) : 0;
const canApply = project ? project.status === 'open' && !isDeadlinePassed && spotsRemaining > 0 : false;

Expand Down Expand Up @@ -449,6 +460,17 @@ export default function ProjectDetailPage({ params }: { params: Promise<{ id: st
<Github className="w-5 h-5 mr-2" />
Repository
</a>
{project.timelineUrl && (
<a
href={project.timelineUrl}
target="_blank"
rel="noopener noreferrer"
className="neo-brutal-btn bg-[var(--dsoc-secondary)] text-white"
>
<Calendar className="w-5 h-5 mr-2" />
Timeline
</a>
)}
{project.websiteUrl && (
<a
href={project.websiteUrl}
Expand Down Expand Up @@ -710,6 +732,33 @@ export default function ProjectDetailPage({ params }: { params: Promise<{ id: st
</p>
</div>

{project.timelineUrl && (
<div className="neo-brutal-card p-6 bg-[var(--dsoc-secondary)] text-white border-[var(--dsoc-dark)]">
<div className="flex items-start justify-between gap-4">
<div>
<h3 className="text-lg font-black flex items-center gap-2">
<Calendar className="w-5 h-5" />
Project Timeline
</h3>
<p className="text-sm mt-2 opacity-90">
See the full schedule, milestones, and key dates before you apply.
</p>
</div>
<span className="inline-flex items-center px-2 py-1 text-xs font-black bg-white text-[var(--dsoc-secondary)] border-2 border-[var(--dsoc-dark)]">
New
</span>
</div>
<a
href={project.timelineUrl}
target="_blank"
rel="noopener noreferrer"
className="neo-brutal-btn bg-white text-[var(--dsoc-secondary)] w-full mt-4"
>
View Timeline
</a>
</div>
)}

{/* Discord Card */}
<div className="neo-brutal-card p-6 dsoc-discord-card">
<div className="text-[var(--dsoc-dark)] dark:text-[var(--dsoc-light)]">
Expand Down
5 changes: 5 additions & 0 deletions models/DSOCProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface IDSOCProject extends Document {
organization: string;
repositoryUrl: string;
websiteUrl?: string;
timelineUrl?: string;
difficulty: 'beginner' | 'intermediate' | 'advanced';
duration: string; // e.g., "3 months", "6 weeks"
technologies: string[];
Expand Down Expand Up @@ -65,6 +66,10 @@ const DSOCProjectSchema = new Schema<IDSOCProject>(
type: String,
trim: true,
},
timelineUrl: {
type: String,
trim: true,
},
difficulty: {
type: String,
enum: ['beginner', 'intermediate', 'advanced'],
Expand Down
Loading