Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
6cfa7a1
Create Committee Model
Games4Doritos Dec 30, 2025
67b37ac
feat: enhance About Us section styling and layout
Oliverr48 Jan 7, 2026
511006d
feat: implement About page with Committee section
Oliverr48 Jan 7, 2026
2583e47
Implemented Committee Model in the backend
Games4Doritos Jan 9, 2026
b1ddbc7
Fix committee member name styling and alignment
Oliverr48 Jan 11, 2026
fb398f2
Merge branch 'main' of https://github.com/codersforcauses/game-dev in…
Oliverr48 Jan 11, 2026
964b84a
Fix navbar to stay fixed at top when scrolling
Oliverr48 Jan 11, 2026
a1ff0f2
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 17, 2026
4d1d367
Added CommitteeAPIView, useCommittee hook and implemented it in frontend
Games4Doritos Jan 18, 2026
76ceb31
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 18, 2026
ec86c09
Revert "Fix navbar to stay fixed at top when scrolling"
Games4Doritos Jan 18, 2026
83c6e99
Previous commit furthered
Games4Doritos Jan 18, 2026
799950e
Altered Committee id field and added tests for Committee Model
Games4Doritos Jan 21, 2026
9748359
Undid some changes to sync up with main
Games4Doritos Jan 21, 2026
c322a67
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 21, 2026
fcbcf59
Implemented Committee's profile pictures into the frontend
Games4Doritos Jan 21, 2026
c6cea36
Formatting + replaced type of topRow and bottomRow
Games4Doritos Jan 21, 2026
2f6dee1
Appeased ESLint and flake8
Games4Doritos Jan 22, 2026
7ba9d24
Reworked one test
Games4Doritos Jan 22, 2026
a63146a
Enacted requested changes 4 and 5
Games4Doritos Jan 23, 2026
a94c8a5
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 24, 2026
aaf204c
Enacted changes 1,2 and 6
Games4Doritos Jan 24, 2026
8da1a0e
Remove ImageIcon import
Games4Doritos Jan 24, 2026
557dd56
Enacted change 3 + misc
Games4Doritos Jan 24, 2026
e73f2e8
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 24, 2026
c256d82
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 24, 2026
34e504e
Simplified some image paths + centered bottom comittee pictures
Games4Doritos Jan 25, 2026
6e9a0e0
Fixed null image responses
Games4Doritos Jan 25, 2026
ff466b4
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 25, 2026
54cb1f3
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 29, 2026
4742905
Merged two migrations
Games4Doritos Jan 29, 2026
2a8504c
Merge branch 'main' into issue-5-About_us/committee_page
Games4Doritos Jan 30, 2026
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
Binary file added client/public/frame.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions client/src/hooks/useCommittee.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useQuery } from "@tanstack/react-query";
import { AxiosError } from "axios";

import api from "@/lib/api";

export type ApiMember = {
name: string;
profile_picture: string;
pronouns: string;
about: string;
};

export function useCommittee() {
return useQuery<ApiMember[], AxiosError>({
queryKey: ["role"],
queryFn: async () => {
const response = await api.get<ApiMember[]>("/about/");
console.log(response.data);
return response.data;
},
retry: (failureCount, error) => {
if (error?.response?.status === 404) {
return false;
}
return failureCount < 3;
},
});
}
185 changes: 185 additions & 0 deletions client/src/pages/about.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import Image from "next/image";

import { ApiMember, useCommittee } from "@/hooks/useCommittee";

export default function AboutPage() {
//const router = useRouter();
//const { id } = router.query;
// don't know if necessary

const { data: committee, isPending, error, isError } = useCommittee();

const topRow: ApiMember[] = [];
const bottomRow: ApiMember[] = [];
//lists that will be populated with member objects in the committee
const roleOrder = [
"President",
"Vice President",
"Secretary",
"Treasurer",
"Marketing",
"Events OCM",
"Projects OCM",
"Fresher Rep",
];

const about = (
<>
<div className="mx-auto max-w-6xl space-y-20 px-6 py-16 md:px-20">
<section className="flex flex-col justify-between gap-12 md:flex-row md:gap-20">
<div className="flex-1">
<h1 className="mb-4 font-jersey10 text-5xl text-primary md:text-6xl">
About Us
</h1>
<div className="mb-6 w-full border-t" aria-hidden="true" />
<div className="space-y-4 font-sans text-base leading-relaxed text-white md:text-lg">
<p>
Description of the clubs aims, why it exists, its mission, etc
etc. Second paragraph here, a second paragraph would be pretty
cool. The more info the better yippee!!
</p>
<p>
Lorem ipsum dolor such and such I can&apos;t remember the rest.
</p>
</div>
</div>
<div className="relative aspect-[4/3] w-full flex-shrink-0 overflow-hidden rounded-2xl bg-light_2 md:w-96 lg:w-[32rem]">
<div className="flex h-full w-full items-center justify-center">
<Image
src="/landing_placeholder.png"
alt="/landing_placeholder.png"
width={128}
height={128}
className="h-[90%] w-[90%]"
/>
</div>
</div>
</section>
</div>
{/* Our Committee Title Section - LIGHT - Full Width */}
<section className="w-full bg-card px-6 py-6 md:px-10 md:py-6">
<div className="mx-auto max-w-6xl">
<h2 className="font-jersey10 text-3xl text-light_2">Our Committee</h2>
</div>
</section>
</>
);

if (isPending) {
for (let i = 0; i < 8; i++) {
if (i < 4) {
topRow.push({
name: "Loading...",
pronouns: "",
profile_picture: "/landing_placeholder.png",
about: "",
});
} else {
bottomRow.push({
name: "Loading...",
pronouns: "",
profile_picture: "/landing_placeholder.png",
about: "",
});
}
}
} else if (isError) {
const errorMessage =
error?.response?.status === 404
? "Committee Members not found."
: "Failed to load Committee Members.";

return (
<>
{about}
<main className="mx-auto min-h-screen max-w-6xl px-6 py-16 md:px-20">
<p className="text-red-500" role="alert">
{errorMessage}
</p>
</main>
</>
);
} else {
for (let i = 0; i < 8; i++) {
if (i < 4) {
topRow.push(committee[i]);
} else {
bottomRow.push(committee[i]);
}
}
}

return (
<main className="min-h-screen bg-background">
{about}
{/* Portraits Section - DARK - Full Width */}
<section className="w-full bg-background px-6 py-10 pt-16 md:px-10">
<div className="mx-auto max-w-6xl">
{/* Top row - 4 Presidents */}
<div className="flex flex-wrap justify-center gap-6 md:gap-10">
{topRow.map((member, idx) => (
<div
key={`top-${idx}`}
className="flex flex-col items-start gap-0"
>
<div className="relative flex h-[11.5625rem] w-[11.25rem] items-center justify-center bg-[url('/frame.png')] bg-contain bg-center bg-no-repeat">
<Image
src={
member.profile_picture === null
? "/landing_placeholder.png"
: member.profile_picture
}
alt="/landing_placeholder.png"
width={106}
height={106}
className="mb-3 h-[6.625rem] w-[6.625rem]"
/>
</div>
<div className="w-[11.25rem] pl-3 text-left font-firaCode text-[0.5rem] leading-tight">
<p className="inline-block bg-card px-2 py-1 text-white">
{member.name} {member.pronouns}
</p>
<p className="inline-block bg-card px-2 py-1 text-primary">
{roleOrder[idx]}
</p>
</div>
</div>
))}
</div>

{/* Bottom row - 4 other roles */}
<div className="mt-10 flex flex-wrap justify-center gap-6 md:gap-10">
{bottomRow.map((member, idx) => (
<div
key={`bottom-${idx}`}
className="flex flex-col items-start gap-0"
>
<div className="relative flex h-[11.5625rem] w-[11.25rem] items-center justify-center bg-[url('/frame.png')] bg-contain bg-center bg-no-repeat">
<Image
src={
member.profile_picture === null
? "/landing_placeholder.png"
: member.profile_picture
}
alt="/landing_placeholder.png"
width={106}
height={106}
className="mb-3 h-[6.625rem] w-[6.625rem] pl-[0.03125rem]"
/>
</div>
<div className="w-[11.25rem] pl-3 text-left font-firaCode text-[0.5rem] leading-tight">
<p className="inline-block bg-card px-2 py-1 text-white">
{member.name} {member.pronouns}
</p>
<p className="inline-block bg-card px-2 py-1 text-primary">
{roleOrder[4 + idx]}
</p>
</div>
</div>
))}
</div>
</div>
</section>
</main>
);
}
7 changes: 6 additions & 1 deletion server/game_dev/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.contrib import admin
from .models import Member, Event
from .models import Member, Event, Committee


class MemberAdmin(admin.ModelAdmin):
Expand All @@ -10,5 +10,10 @@ class EventAdmin(admin.ModelAdmin):
list_display = ("name", "date", "location", "publicationDate")


class CommitteeAdmin(admin.ModelAdmin):
pass


admin.site.register(Member, MemberAdmin)
admin.site.register(Event, EventAdmin)
admin.site.register(Committee, CommitteeAdmin)
20 changes: 20 additions & 0 deletions server/game_dev/migrations/0005_committee.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.1.15 on 2026-01-09 09:46

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('game_dev', '0004_alter_event_date'),
]

operations = [
migrations.CreateModel(
name='Committee',
fields=[
('id', models.OneToOneField(on_delete=django.db.models.deletion.DO_NOTHING, primary_key=True, serialize=False, to='game_dev.member')),
],
),
]
20 changes: 20 additions & 0 deletions server/game_dev/migrations/0006_committee_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.1.15 on 2026-01-09 09:59

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('game_dev', '0005_committee'),
]

operations = [
migrations.AddField(
model_name='committee',
name='role',
field=models.CharField(choices=[('P', 'President'), ('VP', 'Vice-President'), ('SEC', 'Secretary'),
('TRE', 'Treasurer'), ('MARK', 'Marketing'), ('EV', 'Events OCM'),
('PRO', 'Projects OCM'), ('FRE', 'Fresher Rep')], default='FRE', max_length=9),
),
]
19 changes: 19 additions & 0 deletions server/game_dev/migrations/0007_alter_committee_id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.1.15 on 2026-01-21 07:59

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('game_dev', '0006_committee_role'),
]

operations = [
migrations.AlterField(
model_name='committee',
name='id',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='game_dev.member'),
),
]
20 changes: 20 additions & 0 deletions server/game_dev/migrations/0008_alter_committee_role.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 5.1.15 on 2026-01-21 08:11

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('game_dev', '0007_alter_committee_id'),
]

operations = [
migrations.AlterField(
model_name='committee',
name='role',
field=models.CharField(choices=[('P', 'President'), ('VP', 'Vice-President'), ('SEC', 'Secretary'),
('TRE', 'Treasurer'), ('MARK', 'Marketing'), ('EV', 'Events OCM'),
('PRO', 'Projects OCM'), ('FRE', 'Fresher Rep')], default='FRE', max_length=9, unique=True),
),
]
14 changes: 14 additions & 0 deletions server/game_dev/migrations/0009_merge_20260129_2104.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 5.1.15 on 2026-01-29 13:04

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('game_dev', '0005_alter_member_profile_picture'),
('game_dev', '0008_alter_committee_role'),
]

operations = [
]
21 changes: 21 additions & 0 deletions server/game_dev/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,24 @@ class Event(models.Model):

def __str__(self):
return self.name


class Committee(models.Model):
id = models.OneToOneField(Member, on_delete=models.CASCADE, primary_key=True)
roles = {
"P": "President",
"VP": "Vice-President",
"SEC": "Secretary",
"TRE": "Treasurer",
"MARK": "Marketing",
"EV": "Events OCM",
"PRO": "Projects OCM",
"FRE": "Fresher Rep"
}
role = models.CharField(max_length=9, choices=roles, default="FRE", unique=True)

def get_member(self):
return self.id

def __str__(self):
return self.id.name
Loading