Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ddf7b54
Bump the production-dependencies group across 1 directory with 8 updates
dependabot[bot] Apr 9, 2026
b355887
ATM-54 filter nominees by active cycle on nomination form
b-at-neu Apr 10, 2026
c45750c
Merge pull request #58 from SGAOperations/dependabot/npm_and_yarn/pro…
b-at-neu Apr 10, 2026
aa42efb
Merge pull request #59 from SGAOperations/54-filter-nominees-by-activ…
b-at-neu Apr 10, 2026
b8a6727
Bump lucide-react from 0.575.0 to 1.8.0
dependabot[bot] Apr 11, 2026
1061679
Bump the development-dependencies group across 1 directory with 6 upd…
dependabot[bot] Apr 25, 2026
28d2591
Merge pull request #61 from SGAOperations/dependabot/npm_and_yarn/luc…
b-at-neu Apr 27, 2026
4976d07
Merge pull request #65 from SGAOperations/dependabot/npm_and_yarn/dev…
b-at-neu Apr 27, 2026
00384c8
Bump the production-dependencies group across 1 directory with 6 updates
dependabot[bot] Apr 27, 2026
3efca8c
Merge pull request #67 from SGAOperations/dependabot/npm_and_yarn/pro…
b-at-neu Apr 27, 2026
2191c0d
#68 remove unused function
b-at-neu Apr 27, 2026
1a53768
#68 get active nominations for admin page
b-at-neu Apr 27, 2026
ac3115c
#68 fix tailwind format
b-at-neu Apr 27, 2026
ad44de6
Merge pull request #69 from SGAOperations/68-filter-admin-nominations…
b-at-neu Apr 27, 2026
61fcd25
#70 remove unused function
b-at-neu Apr 27, 2026
a4a10b5
#70 remove unused function
b-at-neu Apr 27, 2026
cacd1c3
#70 only get active applications
b-at-neu Apr 27, 2026
c84cffe
#70 update error message
b-at-neu Apr 27, 2026
0180f4d
Merge pull request #71 from SGAOperations/70-dont-allow-dashboard-to-…
b-at-neu Apr 27, 2026
2569c1b
Bump version from 1.5.1 to 1.5.2
b-at-neu Apr 27, 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
10 changes: 6 additions & 4 deletions app/admin/nominations/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { getAllNominations } from '@/lib/data/nominations';
import { getActiveNominations } from '@/lib/data/nominations';
import { getSettings } from '@/lib/data/settings';
import { createClient } from '@/lib/supabase/server';
import { redirect } from 'next/navigation';
import NominationsManager from '@/components/NominationsManager';

export default async function NominationsAdminPage() {
const supabase = await createClient();
const { data: { user } } = await supabase.auth.getUser();
const {
data: { user },
} = await supabase.auth.getUser();

if (!user) {
redirect('/login');
}

const nominations = await getAllNominations();
const nominations = await getActiveNominations();
const settings = await getSettings();

return (
<div className="container max-w-[1600px] mx-auto py-6 px-4">
<div className="container max-w-400 mx-auto py-6 px-4">
<div className="mb-6">
<h1 className="text-4xl font-bold">Manage Nominations</h1>
<p className="text-muted-foreground mt-2">
Expand Down
16 changes: 10 additions & 6 deletions app/dashboard/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { getApplicationByNuidWithNominations } from '@/lib/data/applications';
import { getActiveApplicationByNuidWithNominations } from '@/lib/data/applications';
import { getSettings } from '@/lib/data/settings';
import UserDashboard from '@/components/UserDashboard';

export default async function DashboardPage() {
const settings = await getSettings();

return (
<div className="container max-w-[1600px] mx-auto py-3 sm:py-6 px-3 sm:px-4">
<div className="mb-3 sm:mb-6">
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold">User Dashboard</h1>
<p className="text-sm sm:text-base text-muted-foreground mt-2">View your application status and nomination count</p>
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold">
User Dashboard
</h1>
<p className="text-sm sm:text-base text-muted-foreground mt-2">
View your application status and nomination count
</p>
</div>
<UserDashboard
getApplicationByNuid={getApplicationByNuidWithNominations}
<UserDashboard
getApplicationByNuid={getActiveApplicationByNuidWithNominations}
settings={settings}
/>
</div>
Expand Down
322 changes: 243 additions & 79 deletions components/UserDashboard.tsx

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions lib/actions/nominations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ export async function createNomination(data: NominationData) {
throw new Error('You cannot nominate yourself for Senator');
}

// Validate: Nominee must exist and get their constituency info
// Validate: Nominee must exist in the active cycle and get their constituency info
const activeCycle = await getActiveCycle();
const nomineeApp = await db.application.findFirst({
where: { fullName: data.nominee },
where: { fullName: data.nominee, cycleId: activeCycle.id },
select: {
constituency: true,
communityConstituencyId: true,
Expand Down Expand Up @@ -86,8 +87,6 @@ export async function createNomination(data: NominationData) {
}

// Create nomination with PENDING status
const activeCycle = await getActiveCycle();

await db.nomination.create({
data: {
fullName: data.fullName,
Expand Down
47 changes: 26 additions & 21 deletions lib/data/applications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,9 @@ import { db } from '@/lib/db';
import { Application } from '@prisma/client';
import { getActiveCycle } from '@/lib/data/cycles';

export async function getApplications() {
return db.application.findMany();
}

export async function getApplicationByNuid(nuid: string) {
return db.application.findUnique({
where: { nuid },
});
}

export async function getApplicationByNuidWithNominations(nuid: string) {
export async function getActiveApplicationByNuidWithNominations(nuid: string) {
const application = await db.application.findUnique({
where: { nuid },
where: { nuid, cycle: { isActive: true } },
include: {
communityConstituency: {
select: { name: true },
Expand Down Expand Up @@ -75,7 +65,10 @@ export async function getApplicationWithNominations(id: string) {
});

const endorsements = await db.endorsement.findMany({
where: { applicantName: application.fullName, cycleId: application.cycleId },
where: {
applicantName: application.fullName,
cycleId: application.cycleId,
},
orderBy: { createdAt: 'desc' },
});

Expand All @@ -91,7 +84,10 @@ export async function getApplicationWithNominations(id: string) {
};
}

export async function getApplicationWithNominationsByCycleId(cycleId: string, id: string) {
export async function getApplicationWithNominationsByCycleId(
cycleId: string,
id: string,
) {
const application = await db.application.findUnique({
where: { id },
include: {
Expand Down Expand Up @@ -176,21 +172,25 @@ export async function getApplicationsWithNominationCounts() {
}

export async function getNominationFormData() {
// Get all nominees (applications)
const activeCycle = await getActiveCycle();

// Get nominees from the active cycle only
const allNominees = await db.application.findMany({
select: {
fullName: true,
where: { cycleId: activeCycle.id },
select: {
fullName: true,
email: true,
nominationFormPdfUrl: true
nominationFormPdfUrl: true,
},
});

// Filter out nominees who have uploaded a paper nomination form
const nominees = allNominees
.filter(nominee => !nominee.nominationFormPdfUrl)
.filter((nominee) => !nominee.nominationFormPdfUrl)
.map(({ fullName, email }) => ({ fullName, email }));

const constituencies = await db.application.findMany({
where: { cycleId: activeCycle.id },
select: { constituency: true },
distinct: ['constituency'],
});
Expand All @@ -208,7 +208,9 @@ export async function getNominationFormData() {
};
}

export async function getApplicationsWithNominationCountsByCycleId(cycleId: string) {
export async function getApplicationsWithNominationCountsByCycleId(
cycleId: string,
) {
const applications = await db.application.findMany({
where: { cycleId },
include: {
Expand Down Expand Up @@ -250,7 +252,10 @@ export async function getApplicationsWithNominationCountsByCycleId(cycleId: stri
}

export async function createOrUpdateApplication(
data: Omit<Application, 'id' | 'createdAt' | 'nominationFormPdfUrl' | 'cycleId'>,
data: Omit<
Application,
'id' | 'createdAt' | 'nominationFormPdfUrl' | 'cycleId'
>,
) {
const activeCycle = await getActiveCycle();

Expand Down
22 changes: 8 additions & 14 deletions lib/data/nominations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,6 @@ const Status = {
MANUAL_REVIEW: 'MANUAL_REVIEW',
} as const;

export async function getNominations() {
return db.nomination.findMany({
include: {
communityConstituency: {
select: { name: true },
},
},
orderBy: { createdAt: 'desc' },
});
}

export async function getNominationsByCycleId(cycleId: string) {
return db.nomination.findMany({
where: { cycleId },
Expand All @@ -33,8 +22,9 @@ export async function getNominationsByCycleId(cycleId: string) {
});
}

export async function getAllNominations() {
export async function getActiveNominations() {
return db.nomination.findMany({
where: { cycle: { isActive: true } },
include: {
communityConstituency: {
select: { name: true },
Expand All @@ -44,7 +34,9 @@ export async function getAllNominations() {
});
}

export async function getNominationsByStatus(status: 'PENDING' | 'APPROVED' | 'REJECTED') {
export async function getNominationsByStatus(
status: 'PENDING' | 'APPROVED' | 'REJECTED',
) {
return db.nomination.findMany({
where: { status },
include: {
Expand Down Expand Up @@ -135,7 +127,9 @@ export async function getNomineesWithMinVotes(minVotes: number) {
.sort((a, b) => b.count - a.count);
}

export async function createNomination(data: Omit<Nomination, 'id' | 'createdAt' | 'status' | 'cycleId'>) {
export async function createNomination(
data: Omit<Nomination, 'id' | 'createdAt' | 'status' | 'cycleId'>,
) {
// Validate: Can't nominate yourself
if (data.fullName === data.nominee) {
throw new Error('You cannot nominate yourself for Senator');
Expand Down
Loading
Loading