Skip to content

Commit 02ecb92

Browse files
Merge pull request #43 from devweekends/add-project-timeline-link
add: Add project timeline url
2 parents fddcc15 + 104ec5d commit 02ecb92

6 files changed

Lines changed: 96 additions & 3 deletions

File tree

app/admin/dsoc/projects/[id]/edit/page.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export default function EditProjectPage() {
4646
organization: '',
4747
repositoryUrl: '',
4848
websiteUrl: '',
49+
timelineUrl: '',
4950
difficulty: 'intermediate',
5051
duration: '3 months',
5152
technologies: '',
@@ -104,6 +105,7 @@ export default function EditProjectPage() {
104105
organization: project.organization || '',
105106
repositoryUrl: project.repositoryUrl || '',
106107
websiteUrl: project.websiteUrl || '',
108+
timelineUrl: project.timelineUrl || '',
107109
difficulty: project.difficulty || 'intermediate',
108110
duration: project.duration || '3 months',
109111
technologies: Array.isArray(project.technologies) ? project.technologies.join(', ') : '',
@@ -221,6 +223,7 @@ export default function EditProjectPage() {
221223
organization: formData.organization,
222224
repositoryUrl: formData.repositoryUrl,
223225
websiteUrl: formData.websiteUrl,
226+
timelineUrl: formData.timelineUrl,
224227
difficulty: formData.difficulty,
225228
duration: formData.duration,
226229
technologies: formData.technologies.split(',').map(s => s.trim()).filter(Boolean),
@@ -630,6 +633,18 @@ export default function EditProjectPage() {
630633
placeholder="e.g., 2025, Summer 2025"
631634
/>
632635
</div>
636+
637+
<div>
638+
<label className="block font-bold text-sm mb-2">Timeline Link</label>
639+
<input
640+
type="url"
641+
name="timelineUrl"
642+
value={formData.timelineUrl}
643+
onChange={handleChange}
644+
className="neo-brutal-input"
645+
placeholder="https://example.com/timeline"
646+
/>
647+
</div>
633648
</div>
634649

635650
{/* Requirements */}

app/admin/dsoc/projects/new/page.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default function NewProjectPage() {
4040
organization: '',
4141
repositoryUrl: '',
4242
websiteUrl: '',
43+
timelineUrl: '',
4344
difficulty: 'intermediate',
4445
duration: '3 months',
4546
technologies: '',
@@ -541,6 +542,18 @@ export default function NewProjectPage() {
541542
placeholder="e.g., 2025, Summer 2025"
542543
/>
543544
</div>
545+
546+
<div>
547+
<label className="block font-bold text-sm mb-2">Timeline Link</label>
548+
<input
549+
type="url"
550+
name="timelineUrl"
551+
value={formData.timelineUrl}
552+
onChange={handleChange}
553+
className="neo-brutal-input"
554+
placeholder="https://example.com/timeline"
555+
/>
556+
</div>
544557
</div>
545558

546559
{/* Requirements */}

app/api/dsoc/applications/route.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@ async function getMenteeFromToken(request: NextRequest) {
1818
}
1919
}
2020

21+
function getDeadlineEnd(dateString: string) {
22+
const [year, month, day] = dateString.split('-').map(Number);
23+
24+
if (!year || !month || !day) {
25+
return new Date(dateString);
26+
}
27+
28+
return new Date(year, month - 1, day, 23, 59, 59, 999);
29+
}
30+
2131
// Helper to get mentor from token
2232
async function getMentorFromToken(request: NextRequest) {
2333
const token = request.cookies.get('dsoc-mentor-token')?.value;
@@ -59,7 +69,7 @@ export async function GET(request: NextRequest) {
5969
.select('_id')
6070
.lean();
6171

62-
const mentorProjectIds = mentorProjects.map((project) => project._id.toString());
72+
const mentorProjectIds = mentorProjects.map((project) => String(project._id));
6373

6474
if (projectId) {
6575
if (!mentorProjectIds.includes(projectId)) {
@@ -129,7 +139,7 @@ export async function POST(request: NextRequest) {
129139
);
130140
}
131141

132-
if (new Date() > new Date(project.applicationDeadline)) {
142+
if (new Date() > getDeadlineEnd(project.applicationDeadline)) {
133143
return NextResponse.json(
134144
{ success: false, error: 'Application deadline has passed' },
135145
{ status: 400 }

app/dsoc/apply/[id]/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ export default function ApplyPage({ params }: { params: Promise<{ id: string }>
863863
<option value="UTC-05:00">UTC-05:00 (Eastern Time)</option>
864864
<option value="UTC+00:00">UTC+00:00 (London)</option>
865865
<option value="UTC+01:00">UTC+01:00 (Central Europe)</option>
866+
<option value="UTC+05:00">UTC+05:00 (Pakistan)</option>
866867
<option value="UTC+05:30">UTC+05:30 (India)</option>
867868
<option value="UTC+08:00">UTC+08:00 (Singapore/China)</option>
868869
<option value="UTC+09:00">UTC+09:00 (Japan/Korea)</option>

app/dsoc/projects/[id]/page.tsx

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ interface Project {
4141
organization: string;
4242
repositoryUrl: string;
4343
websiteUrl?: string;
44+
timelineUrl?: string;
4445
difficulty: 'beginner' | 'intermediate' | 'advanced';
4546
duration: string;
4647
technologies: string[];
@@ -367,7 +368,17 @@ export default function ProjectDetailPage({ params }: { params: Promise<{ id: st
367368
});
368369
};
369370

370-
const isDeadlinePassed = project ? new Date() >= new Date(project.applicationDeadline) : false;
371+
const getDeadlineEnd = (dateString: string) => {
372+
const [year, month, day] = dateString.split('-').map(Number);
373+
374+
if (!year || !month || !day) {
375+
return new Date(dateString);
376+
}
377+
378+
return new Date(year, month - 1, day, 23, 59, 59, 999);
379+
};
380+
381+
const isDeadlinePassed = project ? new Date() > getDeadlineEnd(project.applicationDeadline) : false;
371382
const spotsRemaining = project ? project.maxMentees - (project.selectedMentees?.length || 0) : 0;
372383
const canApply = project ? project.status === 'open' && !isDeadlinePassed && spotsRemaining > 0 : false;
373384

@@ -449,6 +460,17 @@ export default function ProjectDetailPage({ params }: { params: Promise<{ id: st
449460
<Github className="w-5 h-5 mr-2" />
450461
Repository
451462
</a>
463+
{project.timelineUrl && (
464+
<a
465+
href={project.timelineUrl}
466+
target="_blank"
467+
rel="noopener noreferrer"
468+
className="neo-brutal-btn bg-[var(--dsoc-secondary)] text-white"
469+
>
470+
<Calendar className="w-5 h-5 mr-2" />
471+
Timeline
472+
</a>
473+
)}
452474
{project.websiteUrl && (
453475
<a
454476
href={project.websiteUrl}
@@ -710,6 +732,33 @@ export default function ProjectDetailPage({ params }: { params: Promise<{ id: st
710732
</p>
711733
</div>
712734

735+
{project.timelineUrl && (
736+
<div className="neo-brutal-card p-6 bg-[var(--dsoc-secondary)] text-white border-[var(--dsoc-dark)]">
737+
<div className="flex items-start justify-between gap-4">
738+
<div>
739+
<h3 className="text-lg font-black flex items-center gap-2">
740+
<Calendar className="w-5 h-5" />
741+
Project Timeline
742+
</h3>
743+
<p className="text-sm mt-2 opacity-90">
744+
See the full schedule, milestones, and key dates before you apply.
745+
</p>
746+
</div>
747+
<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)]">
748+
New
749+
</span>
750+
</div>
751+
<a
752+
href={project.timelineUrl}
753+
target="_blank"
754+
rel="noopener noreferrer"
755+
className="neo-brutal-btn bg-white text-[var(--dsoc-secondary)] w-full mt-4"
756+
>
757+
View Timeline
758+
</a>
759+
</div>
760+
)}
761+
713762
{/* Discord Card */}
714763
<div className="neo-brutal-card p-6 dsoc-discord-card">
715764
<div className="text-[var(--dsoc-dark)] dark:text-[var(--dsoc-light)]">

models/DSOCProject.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export interface IDSOCProject extends Document {
77
organization: string;
88
repositoryUrl: string;
99
websiteUrl?: string;
10+
timelineUrl?: string;
1011
difficulty: 'beginner' | 'intermediate' | 'advanced';
1112
duration: string; // e.g., "3 months", "6 weeks"
1213
technologies: string[];
@@ -65,6 +66,10 @@ const DSOCProjectSchema = new Schema<IDSOCProject>(
6566
type: String,
6667
trim: true,
6768
},
69+
timelineUrl: {
70+
type: String,
71+
trim: true,
72+
},
6873
difficulty: {
6974
type: String,
7075
enum: ['beginner', 'intermediate', 'advanced'],

0 commit comments

Comments
 (0)