Skip to content

Commit f880414

Browse files
Merge branch 'main' into issue-55-Add_member_social_media_info
2 parents fb4123c + 050a2dc commit f880414

14 files changed

Lines changed: 455 additions & 42 deletions

client/src/components/main/Navbar.tsx

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,44 +18,41 @@ export default function Navbar() {
1818

1919
return (
2020
<>
21-
<header className="sticky top-0 z-50 flex h-24 w-full flex-wrap items-center justify-center rounded-md border-b border-border/20 bg-background px-20 font-jersey10">
22-
<Link
23-
href="/"
24-
className="flex flex-none items-center gap-3 text-2xl md:mr-5"
25-
>
26-
<Image
27-
src="/game_dev_club_logo.svg"
28-
alt="logo"
29-
width={32}
30-
height={32}
31-
className="h-8 w-8"
32-
/>
33-
<span className="sr-only">Game Development UWA</span>
34-
<span aria-hidden="true" className="whitespace-nowrap md:hidden">
35-
GDUWA
36-
</span>
37-
<span
38-
aria-hidden="true"
39-
className="hidden whitespace-nowrap md:inline"
40-
>
41-
Game Development UWA _
42-
</span>
43-
</Link>
44-
45-
<nav className="ml-auto hidden flex-none gap-8 text-xl md:flex">
46-
{navItems.map((item) => (
47-
<Link
48-
key={item.href}
49-
href={item.href}
50-
className="whitespace-nowrap text-foreground/90 transition-colors duration-150 hover:text-primary"
21+
<header className="sticky top-0 z-50 flex h-24 w-full items-center rounded-md border-b border-border/20 bg-background px-20 font-jersey10">
22+
<div className="flex flex-1 items-center">
23+
<Link href="/" className="flex items-center gap-3 text-2xl lg:mr-5">
24+
<Image
25+
src="/game_dev_club_logo.svg"
26+
alt="logo"
27+
width={32}
28+
height={32}
29+
className="h-8 w-8"
30+
/>
31+
<span className="sr-only">Game Development UWA</span>
32+
<span aria-hidden="true" className="whitespace-nowrap md:hidden">
33+
GDUWA
34+
</span>
35+
<span
36+
aria-hidden="true"
37+
className="hidden whitespace-nowrap md:inline"
5138
>
52-
{item.label}
53-
</Link>
54-
))}
55-
</nav>
56-
57-
<div className="ml-auto flex items-center">
58-
<div className="relative md:hidden">
39+
Game Development UWA _
40+
</span>
41+
</Link>
42+
<nav className="ml-auto hidden gap-8 text-xl lg:flex">
43+
{navItems.map((item) => (
44+
<Link
45+
key={item.href}
46+
href={item.href}
47+
className="whitespace-nowrap text-foreground/90 transition-colors duration-150 hover:text-primary"
48+
>
49+
{item.label}
50+
</Link>
51+
))}
52+
</nav>
53+
</div>
54+
<div className="flex items-center lg:hidden">
55+
<div className="relative">
5956
<button
6057
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
6158
className="flex items-center justify-center p-2"

client/src/hooks/useCommittee.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useQuery } from "@tanstack/react-query";
2+
import { AxiosError } from "axios";
3+
4+
import api from "@/lib/api";
5+
6+
export type ApiMember = {
7+
name: string;
8+
profile_picture: string;
9+
pronouns: string;
10+
about: string;
11+
};
12+
13+
export function useCommittee() {
14+
return useQuery<ApiMember[], AxiosError>({
15+
queryKey: ["role"],
16+
queryFn: async () => {
17+
const response = await api.get<ApiMember[]>("/about/");
18+
console.log(response.data);
19+
return response.data;
20+
},
21+
retry: (failureCount, error) => {
22+
if (error?.response?.status === 404) {
23+
return false;
24+
}
25+
return failureCount < 3;
26+
},
27+
});
28+
}

client/src/pages/about.tsx

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import Image from "next/image";
2+
3+
import { ApiMember, useCommittee } from "@/hooks/useCommittee";
4+
5+
export default function AboutPage() {
6+
const { data: committee, isPending, error, isError } = useCommittee();
7+
8+
const topRow: ApiMember[] = [];
9+
const bottomRow: ApiMember[] = [];
10+
//lists that will be populated with member objects in the committee
11+
const roleOrder = [
12+
"President",
13+
"Vice President",
14+
"Secretary",
15+
"Treasurer",
16+
"Marketing",
17+
"Events OCM",
18+
"Projects OCM",
19+
"Fresher Rep",
20+
];
21+
22+
const about = (
23+
<>
24+
<div className="mx-auto max-w-6xl space-y-20 px-6 py-16 md:px-20">
25+
<section className="flex flex-col justify-between gap-12 md:flex-row md:gap-20">
26+
<div className="flex-1">
27+
<h1 className="mb-4 font-jersey10 text-5xl text-primary md:text-6xl">
28+
About Us
29+
</h1>
30+
<div className="mb-6 w-full border-t" aria-hidden="true" />
31+
<div className="space-y-4 font-sans text-base leading-relaxed text-white md:text-lg">
32+
<p>
33+
Description of the clubs aims, why it exists, its mission, etc
34+
etc. Second paragraph here, a second paragraph would be pretty
35+
cool. The more info the better yippee!!
36+
</p>
37+
<p>
38+
Lorem ipsum dolor such and such I can&apos;t remember the rest.
39+
</p>
40+
</div>
41+
</div>
42+
<div className="relative aspect-[4/3] w-full flex-shrink-0 overflow-hidden rounded-2xl bg-light_2 md:w-96 lg:w-[32rem]">
43+
<div className="flex h-full w-full items-center justify-center">
44+
<Image
45+
src="/landing_placeholder.png"
46+
alt="/landing_placeholder.png"
47+
width={128}
48+
height={128}
49+
className="h-[90%] w-[90%]"
50+
/>
51+
</div>
52+
</div>
53+
</section>
54+
</div>
55+
{/* Our Committee Title Section - LIGHT - Full Width */}
56+
<section className="w-full bg-card px-6 py-6 md:px-10 md:py-6">
57+
<div className="mx-auto max-w-6xl">
58+
<h2 className="font-jersey10 text-3xl text-light_2">Our Committee</h2>
59+
</div>
60+
</section>
61+
</>
62+
);
63+
64+
if (isPending) {
65+
for (let i = 0; i < 8; i++) {
66+
if (i < 4) {
67+
topRow.push({
68+
name: "Loading...",
69+
pronouns: "",
70+
profile_picture: "/landing_placeholder.png",
71+
about: "",
72+
});
73+
} else {
74+
bottomRow.push({
75+
name: "Loading...",
76+
pronouns: "",
77+
profile_picture: "/landing_placeholder.png",
78+
about: "",
79+
});
80+
}
81+
}
82+
} else if (isError) {
83+
const errorMessage =
84+
error?.response?.status === 404
85+
? "Committee Members not found."
86+
: "Failed to load Committee Members.";
87+
88+
return (
89+
<>
90+
{about}
91+
<main className="mx-auto min-h-screen max-w-6xl px-6 py-16 md:px-20">
92+
<p className="text-red-500" role="alert">
93+
{errorMessage}
94+
</p>
95+
</main>
96+
</>
97+
);
98+
} else {
99+
for (let i = 0; i < 8; i++) {
100+
if (i < 4) {
101+
topRow.push(committee[i]);
102+
} else {
103+
bottomRow.push(committee[i]);
104+
}
105+
}
106+
}
107+
108+
return (
109+
<main className="min-h-screen bg-background">
110+
{about}
111+
{/* Portraits Section - DARK - Full Width */}
112+
<section className="w-full bg-background px-6 py-10 pt-16 md:px-10">
113+
<div className="mx-auto max-w-6xl">
114+
{/* Top row - 4 Presidents */}
115+
<div className="flex flex-wrap justify-center gap-6 md:gap-10">
116+
{topRow.map((member, idx) => (
117+
<div
118+
key={`top-${idx}`}
119+
className="flex flex-col items-start gap-0"
120+
>
121+
<div className="relative flex h-[11.25rem] w-[11.25rem] items-center justify-center bg-[url('/frame.svg')] bg-contain bg-center bg-no-repeat">
122+
<Image
123+
src={
124+
member.profile_picture === null
125+
? "/landing_placeholder.png"
126+
: member.profile_picture
127+
}
128+
alt="/landing_placeholder.png"
129+
width={108}
130+
height={108}
131+
className="mb-2 h-[6.75rem] w-[6.75rem]"
132+
/>
133+
</div>
134+
<div className="w-[11.25rem] pl-3 text-left font-firaCode text-[0.5rem] leading-tight">
135+
<p className="inline-block bg-card px-2 py-1 text-white">
136+
{member.name} {member.pronouns}
137+
</p>
138+
<p className="inline-block bg-card px-2 py-1 text-primary">
139+
{roleOrder[idx]}
140+
</p>
141+
</div>
142+
</div>
143+
))}
144+
</div>
145+
146+
{/* Bottom row - 4 other roles */}
147+
<div className="mt-10 flex flex-wrap justify-center gap-6 md:gap-10">
148+
{bottomRow.map((member, idx) => (
149+
<div
150+
key={`bottom-${idx}`}
151+
className="flex flex-col items-start gap-0"
152+
>
153+
<div className="relative flex h-[11.25rem] w-[11.25rem] items-center justify-center bg-[url('/frame.svg')] bg-contain bg-center bg-no-repeat">
154+
<Image
155+
src={
156+
member.profile_picture === null
157+
? "/landing_placeholder.png"
158+
: member.profile_picture
159+
}
160+
alt="/landing_placeholder.png"
161+
width={108}
162+
height={108}
163+
className="mb-2 h-[6.75rem] w-[6.75rem]"
164+
/>
165+
</div>
166+
<div className="w-[11.25rem] pl-3 text-left font-firaCode text-[0.5rem] leading-tight">
167+
<p className="inline-block bg-card px-2 py-1 text-white">
168+
{member.name} {member.pronouns}
169+
</p>
170+
<p className="inline-block bg-card px-2 py-1 text-primary">
171+
{roleOrder[4 + idx]}
172+
</p>
173+
</div>
174+
</div>
175+
))}
176+
</div>
177+
</div>
178+
</section>
179+
</main>
180+
);
181+
}

server/game_dev/admin.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
from django.contrib import admin
2-
from .models import Member, Game, Event, GameContributor, GameShowcase, SocialMedia
2+
from .models import Member, Game, Event, GameContributor, GameShowcase, Committee, SocialMedia
3+
4+
35
class SocialMediaInline(admin.TabularInline):
46
model = SocialMedia
57
extra = 1
68

79

810
class MemberAdmin(admin.ModelAdmin):
11+
list_display = ("id", "name", "active", "profile_picture", "about", "pronouns")
12+
search_fields = ["name", "about"]
913
inlines = [SocialMediaInline]
1014

1115

@@ -27,8 +31,13 @@ class GamesAdmin(admin.ModelAdmin):
2731
search_fields = ["name", "description"]
2832

2933

34+
class CommitteeAdmin(admin.ModelAdmin):
35+
raw_id_fields = ["id"]
36+
37+
3038
admin.site.register(Member, MemberAdmin)
3139
admin.site.register(Event, EventAdmin)
3240
admin.site.register(Game, GamesAdmin)
3341
admin.site.register(GameContributor, GameContributorAdmin)
3442
admin.site.register(GameShowcase, GameShowcaseAdmin)
43+
admin.site.register(Committee, CommitteeAdmin)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 5.1.15 on 2026-01-09 09:46
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('game_dev', '0004_alter_event_date'),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name='Committee',
16+
fields=[
17+
('id', models.OneToOneField(on_delete=django.db.models.deletion.DO_NOTHING, primary_key=True, serialize=False, to='game_dev.member')),
18+
],
19+
),
20+
]
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Generated by Django 5.1.15 on 2026-01-09 09:59
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('game_dev', '0005_committee'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='committee',
15+
name='role',
16+
field=models.CharField(choices=[('P', 'President'), ('VP', 'Vice-President'), ('SEC', 'Secretary'),
17+
('TRE', 'Treasurer'), ('MARK', 'Marketing'), ('EV', 'Events OCM'),
18+
('PRO', 'Projects OCM'), ('FRE', 'Fresher Rep')], default='FRE', max_length=9),
19+
),
20+
]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 5.1.15 on 2026-01-21 07:59
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('game_dev', '0006_committee_role'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='committee',
16+
name='id',
17+
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='game_dev.member'),
18+
),
19+
]

0 commit comments

Comments
 (0)