Skip to content

Commit 63caa9d

Browse files
authored
Merge pull request #38 from codersforcauses/issue-15-Create_Sponsors_&_Guests_page
Issue 15 create sponsors & guests page
2 parents 0e734bb + d32952c commit 63caa9d

14 files changed

Lines changed: 238 additions & 30 deletions

File tree

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,4 @@ dist
292292
.DS_Store
293293

294294
opt/
295-
296295
/server/static_files
297-
/server/media

client/.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
REACT_EDITOR=code
22

33
APP_ENV=DEVELOPMENT
4-
NEXT_PUBLIC_BACKEND_URL="http://localhost:8000/api"
4+
NEXT_PUBLIC_BACKEND_URL="http://localhost:8000/api"

client/next.config.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const nextConfig = {
1111
domains: ["squadrone.com.au"],
1212
},
1313
reactStrictMode: true,
14+
images: {
15+
domains: ['localhost', '127.0.0.1', 'squadrone.com.au'],
16+
},
1417
// dumb fix for windows docker
1518
webpack: isWindowsDevContainer()
1619
? (config) => {

client/package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,4 @@
5252
"tailwindcss": "^3.4.17",
5353
"typescript": "^5.8.3"
5454
}
55-
}
55+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import Image from "next/image";
2+
3+
// Type definition for a guest item
4+
type Guest = {
5+
name: string;
6+
description: string;
7+
link: string;
8+
image?: string; // optional photo URL
9+
};
10+
11+
interface GuestSectionProps {
12+
guests: Guest[]; // list of guests passed from parent component
13+
}
14+
15+
// GuestSection component renders the special guests section
16+
const GuestSection = ({ guests }: GuestSectionProps) => {
17+
return (
18+
<div className="mt-12 w-full bg-[#54595F] px-8 py-16">
19+
<h2
20+
className={`text-center font-montserrat text-3xl font-bold leading-[1.15em] text-black`}
21+
>
22+
Special Guests
23+
</h2>
24+
25+
<div className="mx-auto mt-12 grid max-w-6xl grid-cols-1 gap-8 md:grid-cols-2 lg:grid-cols-4">
26+
{guests.map((guest, idx) => (
27+
<div key={idx} className="text-center">
28+
{/* Guest image box */}
29+
<div className="relative mx-auto mb-4 flex h-[200px] w-[200px] items-center justify-center overflow-hidden bg-white shadow-md">
30+
{guest.image ? (
31+
<Image
32+
src={guest.image}
33+
alt={guest.name}
34+
className="h-full w-full object-cover"
35+
fill
36+
/>
37+
) : null}
38+
</div>
39+
40+
{/* Guest name and description */}
41+
<div>
42+
<h3
43+
className={`mb-2 font-montserrat text-lg font-semibold text-white`}
44+
>
45+
{guest.name}
46+
</h3>
47+
<p className={`font-montserrat text-sm text-white`}>
48+
{guest.description}
49+
</p>
50+
<p className={`font-montserrat text-sm text-white`}>
51+
{guest.link && (
52+
<a
53+
href={guest.link}
54+
className="ml-1 underline"
55+
target="_blank"
56+
rel="noopener noreferrer"
57+
>
58+
Link
59+
</a>
60+
)}
61+
</p>
62+
</div>
63+
</div>
64+
))}
65+
</div>
66+
</div>
67+
);
68+
};
69+
70+
export default GuestSection;
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import Image from "next/image";
2+
3+
type Partner = {
4+
name: string;
5+
logo: string;
6+
link: string;
7+
};
8+
9+
interface SponsorSectionProps {
10+
partners: Partner[];
11+
}
12+
13+
const SponsorSection = ({ partners }: SponsorSectionProps) => {
14+
return (
15+
<section className="bg-gray-100 py-10 text-center">
16+
<h2 className={`font-montserrat text-2xl font-bold`}>
17+
Powered By Our{" "}
18+
<span className={`font-montserrat text-orange-500`}>Partners</span>
19+
</h2>
20+
<div className="mt-6 flex flex-wrap justify-center gap-6 px-4">
21+
{partners.map((partner, index) => (
22+
<a
23+
key={index}
24+
href={partner.link}
25+
target="_blank"
26+
rel="noopener noreferrer"
27+
className="flex items-center transition hover:opacity-80"
28+
>
29+
<div className="relative h-16 w-32">
30+
<Image
31+
src={partner.logo}
32+
alt={partner.name}
33+
fill
34+
objectFit="contain"
35+
className="object-contain"
36+
/>
37+
</div>
38+
</a>
39+
))}
40+
</div>
41+
</section>
42+
);
43+
};
44+
45+
export default SponsorSection;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default as GuestSection } from "./GuestSection";
2+
export { default as SponsorSection } from "./SponsorSection";
Lines changed: 71 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,77 @@
1-
import { useState } from "react";
1+
import React, { useEffect, useState } from "react";
22

3-
import { usePings } from "@/hooks/pings";
3+
import { GuestSection, SponsorSection } from "@/components/SponsorsGuests";
44

5-
import { Button } from "../components/ui/button";
5+
type Partner = {
6+
name: string;
7+
logo: string;
8+
link: string;
9+
};
610

7-
export default function Home() {
8-
const [clicked, setClicked] = useState(false);
9-
const { data, isLoading } = usePings({
10-
enabled: clicked,
11-
});
11+
// Type definition for guest data
12+
type Guest = {
13+
name: string;
14+
description: string;
15+
link: string;
16+
photo?: string;
17+
};
18+
19+
const SponsorsAndGuest = () => {
20+
const [partners, setPartners] = useState<Partner[]>([]); // Holds sponsor data
21+
const [guests, setGuests] = useState<Guest[]>([]); // Holds guest data
22+
const [loading, setLoading] = useState(true); // Controls loading state
23+
24+
useEffect(() => {
25+
// Define an async function to fetch data
26+
const fetchData = async () => {
27+
try {
28+
const [partnerRes, guestRes] = await Promise.all([
29+
fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/sponsor/`),
30+
fetch(`${process.env.NEXT_PUBLIC_BACKEND_URL}/sponsor/guests/`),
31+
]);
32+
const partnerData = await partnerRes.json();
33+
const guestData = await guestRes.json();
34+
35+
setPartners(partnerData);
36+
setGuests(guestData);
37+
} catch (error) {
38+
console.error("Error fetching data:", error);
39+
} finally {
40+
setLoading(false);
41+
}
42+
};
43+
44+
fetchData();
45+
}, []);
1246

1347
return (
14-
<>
15-
<h1 className="title-large text-dark">Title Test</h1>
16-
<Button onClick={() => setClicked(true)}>
17-
{isLoading ? "Loading" : "Ping"}
18-
</Button>
19-
<p>
20-
Response from server: <span>{data as string}</span>
21-
</p>
22-
</>
48+
<div className="min-h-screen bg-background">
49+
{/* Page title */}
50+
<div className="pt-20 text-center">
51+
<h1 className={`font-montserrat text-6xl font-semibold leading-none`}>
52+
Guests & Sponsors
53+
</h1>
54+
</div>
55+
{/* Special Guests & Sponsors Section */}
56+
{loading ? (
57+
<p className="text-center text-gray-500">Loading...</p>
58+
) : (
59+
<>
60+
<GuestSection
61+
guests={guests.map((guest) => ({
62+
name: guest.name,
63+
description: guest.description,
64+
link: guest.link,
65+
image: guest.photo, // mapped to 'image' for component
66+
}))}
67+
/>
68+
<div className="mt-16">
69+
<SponsorSection partners={partners} />
70+
</div>
71+
</>
72+
)}
73+
</div>
2374
);
24-
}
75+
};
76+
77+
export default SponsorsAndGuest;

docker/server/entrypoint.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ python manage.py collectstatic --noinput
2121
echo "Creating Django Superuser"
2222
python manage.py createsuperuser --noinput
2323

24+
# Load fixtures
25+
python manage.py loaddata sponsor
26+
2427
# Run inbuilt Django server if ENV is development
2528
if [ "${APP_ENV^^}" = "DEVELOPMENT" ]; then
2629

0 commit comments

Comments
 (0)