Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
ebcdf4a
refactor: Rename `industry` to `studyFields` and update related types…
jason301c Jan 25, 2025
d2f28e8
refactor: update JobFilters type and constants with stricter typing
jason301c Jan 25, 2025
7ca5b8d
refactor: update job and filter types with new enums and interfaces
jason301c Jan 25, 2025
d4ee9d4
Merge remote-tracking branch 'origin/development' into frontend/jason…
jason301c Jan 25, 2025
f086509
refactor: Move fetchJobs.ts from app/api to lib directory
jason301c Jan 25, 2025
ddfc6b2
refactor: Rename fetchJobs file to fetch-jobs for consistency
jason301c Jan 25, 2025
cd30d75
docs: Add API documentation for GET /api/jobs endpoint
jason301c Jan 25, 2025
2f2857e
feat: add pagination and dynamic filters to fetchJobs function
jason301c Jan 25, 2025
2f45d37
refactor: Update job and filter types with new fields and options
jason301c Jan 25, 2025
df18b07
feat: Add total job count to API response and update fetchJobs interface
jason301c Jan 25, 2025
2c77cda
refactor: Simplify job details component and improve error handling i…
jason301c Jan 25, 2025
b739256
refactor: Use environment variable for base URL in fetchJobs
jason301c Jan 25, 2025
455fb07
fix: Add optional chaining to job details arrays to prevent runtime e…
jason301c Jan 25, 2025
d41adcb
chore: run prettier
jason301c Jan 25, 2025
ebb6c79
fix ESLint issues
jason301c Jan 25, 2025
288e025
Merge branch 'development' into frontend/jason/types
jason301c Jan 25, 2025
6760eac
improve server error clarity, avoid leaking server error client side
edwnl Jan 26, 2025
fb0719e
remove mock job data and clean up code
edwnl Jan 26, 2025
425e27c
untrack tsconfig.tsbuildinfo
edwnl Jan 26, 2025
c52a8e6
delete mock data
edwnl Jan 26, 2025
8a1f1d6
cleanup types and refactor context
edwnl Jan 26, 2025
4ce9b6e
migrate to server actions
edwnl Jan 26, 2025
39cc70f
left over from type refactor
edwnl Jan 26, 2025
9ad6ccc
remove mock data - re-implement this later
edwnl Jan 26, 2025
61d8268
comment util functions
edwnl Jan 26, 2025
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
3 changes: 3 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ coverage/
desktop.ini

/repo-to-text/

# TypeScript build info
tsconfig.tsbuildinfo
50 changes: 0 additions & 50 deletions frontend/src/app/api/fetchJobs.ts

This file was deleted.

104 changes: 0 additions & 104 deletions frontend/src/app/api/jobs/route.ts

This file was deleted.

26 changes: 1 addition & 25 deletions frontend/src/app/jobs/[id]/@modal/default.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,5 @@
import JobDetails from "@/components/jobs/details/job-details";

import { Modal, ScrollArea } from "@mantine/core";

const mockJobDetails = {
id: "12345",
title: "Frontend Developer",
company: {
name: "Reserve Bank of Australiaaaaa",
website: "https://techcorp.com",
logo: "https://connect-assets.prosple.com/cdn/ff/LxBzK0I5Jr8vU1WcXce4lf873yPS9Q67rLOugmUXsJI/1568086775/public/styles/scale_and_crop_center_120x120/public/2019-09/Logo-australian-security-intelligence-organisation-asio-120x120-2019.jpg?itok=T1OmQAn3https://connect-assets.prosple.com/cdn/ff/Ayx_liRamnduFSV1FsycoYaBNWIUiZfwkbuzQXDplKU/1568591959/public/styles/scale_and_crop_center_80x80/public/2019-09/Logo-australian-security-intelligence-organisation-asio-120x120-2019.jpg",
},
description:
'<h2>Your role</h2>\r\n\r\n<p><strong>Key responsibilities are as follows:</strong></p>\r\n\r\n<ul>\r\n\t<li>Deploy and configure business systems to meet client needs.</li>\r\n\t<li>Perform systems process mapping and conduct needs analysis sessions with clients.</li>\r\n\t<li>Ensure seamless integration with existing infrastructure and processes.</li>\r\n\t<li>Customize system settings to optimize performance and functionality.</li>\r\n\t<li>Ensure compliance with industry standards and best practices.</li>\r\n\t<li>Conduct thorough testing and validation of system implementations.</li>\r\n</ul>\r\n\r\n<h2>About you</h2>\r\n\r\n<p><strong>The ideal candidate will have:</strong></p>\r\n\r\n<ul>\r\n\t<li>A recent third-level qualification in a tech-focused discipline.</li>\r\n\t<li>A base-level understanding of system architecture and design principles.</li>\r\n\t<li>Exposure to database management and data integration techniques is a bonus.</li>\r\n\t<li>A willingness to learn and enthusiasm for digital trends.</li>\r\n</ul>\r\n\r\n<h2>Compensation &amp; benefits</h2>\r\n\r\n<p>Enjoy a competitive salary, free weekly lunches, social events, flexible working options, and modern offices in the CBD.</p>\r\n\r\n<h2>Training &amp; development</h2>\r\n\r\n<p>Benefit from mentoring, coaching, and both internal and external training programs to enhance your career skills.</p>\r\n\r\n<h2>Career progression</h2>\r\n\r\n<p>Opportunities for career advancement as BlueRock Digital continues to grow, with the potential to take on more senior roles.</p>\r\n\r\n<p><a href="https://airtable.com/appIhfpXSddESkxG1/pagK6WyrT72pcRfvo/form?prefill_Title=Graduate%20Consultant%20-%20Digital%20Systems&amp;prefill_Original%20Source%20Link=https%3A%2F%2Fapply.workable.com%2Fthe-blue-rock%2Fj%2F983307A690%2F" rel="noopener" target="_blank">Report this job</a></p>',
type: "Graduate",
locations: ["VIC", "NSW", "TAS", "OTHERS", "QLD"],
studyFields: ["IT & Computer Science", "Engineering & Mathematics"],
workingRights: ["AUS_CITIZEN", "OTHER_RIGHTS"],
applicationUrl: "https://careers.mcdonalds.com.au/",
closeDate: "2025-01-15T00:00:00Z",
createdAt: "2025-01-01T00:00:00Z",
updatedAt: "2025-01-01T00:00:00Z",
};

export default function JobModal() {
return (
<Modal
Expand All @@ -30,8 +8,6 @@ export default function JobModal() {
size="lg"
title="Job Details"
scrollAreaComponent={ScrollArea}
>
<JobDetails {...mockJobDetails} />
</Modal>
></Modal>
);
}
67 changes: 67 additions & 0 deletions frontend/src/app/jobs/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// /src/app/jobs/actions.ts
"use server";

import { MongoClient, ObjectId } from "mongodb";
import { JobFilters } from "@/types/filters";
import { Job } from "@/types/job";
import serializeJob from "@/lib/utils";

const PAGE_SIZE = 20;

export interface MongoJob extends Omit<Job, "id"> {
_id: ObjectId;
}

export async function getJobs(filters: Partial<JobFilters>): Promise<Job[]> {
if (!process.env.MONGODB_URI) {
throw new Error(
"MongoDB URI is not configured. Please check environment variables.",
);
}

const client = new MongoClient(process.env.MONGODB_URI ?? "");

try {
await client.connect();
const collection = client.db("default").collection("active_jobs");

const query = {
outdated: false,
...(filters.workingRights?.length && {
working_rights: { $in: filters.workingRights },
}),
...(filters.jobTypes?.length && { type: { $in: filters.jobTypes } }),
...(filters.industryFields?.length && {
industry_field: { $in: filters.industryFields },
}),
...(filters.search && {
$or: [
{ title: { $regex: filters.search, $options: "i" } },
{ "company.name": { $regex: filters.search, $options: "i" } },
],
}),
};

const page = filters.page || 1;
const skip = (page - 1) * PAGE_SIZE;

const jobs = (await collection
.find(query)
.skip(skip)
.limit(PAGE_SIZE)
.toArray()) as MongoJob[];

return jobs.map(serializeJob);
} catch (error) {
console.error("Server Error:", {
error,
timestamp: new Date().toISOString(),
filters,
});
throw new Error(
"Failed to fetch jobs from the server. Check the server console for more details.",
);
} finally {
await client.close();
}
}
26 changes: 24 additions & 2 deletions frontend/src/app/jobs/error.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
// frontend/src/app/jobs/error.tsx
"use client";
export default function JobError() {
return <div>Job Error</div>;

import { useEffect } from "react";
import { Text, Button } from "@mantine/core";

export default function JobError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
console.error(error);
}, [error]);

return (
<div className="flex flex-col items-center gap-4 p-4">
<Text>
Failed to render jobs page. Check the console for more details.
</Text>
<Button onClick={reset}>Try again</Button>
</div>
);
}
2 changes: 1 addition & 1 deletion frontend/src/app/jobs/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FilterProvider } from "@/context/jobs/filter-provider";
import { FilterProvider } from "@/context/filter/filter-provider";
import { PropsWithChildren } from "react";

export default function JobsLayout({ children }: PropsWithChildren) {
Expand Down
31 changes: 6 additions & 25 deletions frontend/src/app/jobs/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,18 @@ import FilterSection from "@/components/jobs/filters/filter-section";
import JobList from "@/components/jobs/details/job-list";
import JobDetails from "@/components/jobs/details/job-details";
import { Title } from "@mantine/core";
import { fetchJobs } from "@/app/api/fetchJobs";
import { JobFilters } from "@/types/filters";
import { getJobs } from "@/app/jobs/actions";

export default async function JobsPage({
searchParams,
}: {
searchParams: Promise<Partial<JobFilters>>;
}) {
const params = await searchParams;
await fetchJobs(params);

const mockJobDetails = {
id: "12345",
title: "Frontend Developer",
company: {
name: "Reserve Bank of Australiaaaaa",
website: "https://techcorp.com",
logo: "https://connect-assets.prosple.com/cdn/ff/LxBzK0I5Jr8vU1WcXce4lf873yPS9Q67rLOugmUXsJI/1568086775/public/styles/scale_and_crop_center_120x120/public/2019-09/Logo-australian-security-intelligence-organisation-asio-120x120-2019.jpg?itok=T1OmQAn3https://connect-assets.prosple.com/cdn/ff/Ayx_liRamnduFSV1FsycoYaBNWIUiZfwkbuzQXDplKU/1568591959/public/styles/scale_and_crop_center_80x80/public/2019-09/Logo-australian-security-intelligence-organisation-asio-120x120-2019.jpg",
},
description:
'<h2>Your role</h2>\r\n\r\n<p><strong>Key responsibilities are as follows:</strong></p>\r\n\r\n<ul>\r\n\t<li>Deploy and configure business systems to meet client needs.</li>\r\n\t<li>Perform systems process mapping and conduct needs analysis sessions with clients.</li>\r\n\t<li>Ensure seamless integration with existing infrastructure and processes.</li>\r\n\t<li>Customize system settings to optimize performance and functionality.</li>\r\n\t<li>Ensure compliance with industry standards and best practices.</li>\r\n\t<li>Conduct thorough testing and validation of system implementations.</li>\r\n</ul>\r\n\r\n<h2>About you</h2>\r\n\r\n<p><strong>The ideal candidate will have:</strong></p>\r\n\r\n<ul>\r\n\t<li>A recent third-level qualification in a tech-focused discipline.</li>\r\n\t<li>A base-level understanding of system architecture and design principles.</li>\r\n\t<li>Exposure to database management and data integration techniques is a bonus.</li>\r\n\t<li>A willingness to learn and enthusiasm for digital trends.</li>\r\n</ul>\r\n\r\n<h2>Compensation &amp; benefits</h2>\r\n\r\n<p>Enjoy a competitive salary, free weekly lunches, social events, flexible working options, and modern offices in the CBD.</p>\r\n\r\n<h2>Training &amp; development</h2>\r\n\r\n<p>Benefit from mentoring, coaching, and both internal and external training programs to enhance your career skills.</p>\r\n\r\n<h2>Career progression</h2>\r\n\r\n<p>Opportunities for career advancement as BlueRock Digital continues to grow, with the potential to take on more senior roles.</p>\r\n\r\n<p><a href="https://airtable.com/appIhfpXSddESkxG1/pagK6WyrT72pcRfvo/form?prefill_Title=Graduate%20Consultant%20-%20Digital%20Systems&amp;prefill_Original%20Source%20Link=https%3A%2F%2Fapply.workable.com%2Fthe-blue-rock%2Fj%2F983307A690%2F" rel="noopener" target="_blank">Report this job</a></p>',
type: "Graduate",
locations: ["VIC", "NSW", "TAS", "OTHERS", "QLD"],
studyFields: ["IT & Computer Science", "Engineering & Mathematics"],
workingRights: ["AUS_CITIZEN", "OTHER_RIGHTS"],
applicationUrl: "https://careers.mcdonalds.com.au/",
closeDate: "2025-01-15T00:00:00Z",
createdAt: "2025-01-01T00:00:00Z",
updatedAt: "2025-01-01T00:00:00Z",
};
// https://nextjs.org/docs/app/api-reference/file-conventions/page#searchparams-optional
// searchParams is a promise that resolves to an object containing the search
// parameters of the current URL.
const jobs = await getJobs(await searchParams);

return (
<div className="space-y-4">
Expand All @@ -45,10 +27,9 @@ export default async function JobsPage({
<JobList />
</div>

{/* Sticky Job Details - hidden on mobile, 70% on desktop */}
<div className="hidden lg:block lg:w-[65%]">
<div className="overflow-y-auto h-[calc(100vh-330px)]">
<JobDetails {...mockJobDetails} />
<JobDetails job={jobs[0]} />
</div>
</div>
</div>
Expand Down
Loading
Loading