diff --git a/src/app/committees/[shortName]/Nav.tsx b/src/app/committees/[shortName]/Nav.tsx index 83c2173a6..13ed67b43 100644 --- a/src/app/committees/[shortName]/Nav.tsx +++ b/src/app/committees/[shortName]/Nav.tsx @@ -1,28 +1,34 @@ 'use client' import { SubPageNavBar, SubPageNavBarItem } from '@/components/NavBar/SubPageNavBar/SubPageNavBar' -import { faArrowLeft, faCog, faInfo, faUsers } from '@fortawesome/free-solid-svg-icons' +import { faArrowLeft, faCog, faInfo, faScroll, faUsers } from '@fortawesome/free-solid-svg-icons' import { usePathname } from 'next/navigation' +import type { AuthResultTypeAny } from '@/auth/authorizer/AuthResult' type PropTypes = { - shortName: string + shortName: string, + canReadCommitteeApplication: AuthResultTypeAny } -export default function Nav({ shortName }: PropTypes) { +export default function Nav({ shortName, canReadCommitteeApplication }: PropTypes) { const pathname = usePathname() - const settingsPath = `/committees/${shortName}/admin` + const adminPath = `/committees/${shortName}/admin` + const readPeriodesPath = `/committees/${shortName}/applicationPeriods` const membersPath = `/committees/${shortName}/members` const aboutPath = `/committees/${shortName}/about` return ( - Innstillinger - Members - About + Innstillinger + {canReadCommitteeApplication.authorized && + Søknadsperioder + } + Medlemmer + Om - Back + Tilbake ) diff --git a/src/app/committees/[shortName]/applicationPeriods/[participationId]/page.module.scss b/src/app/committees/[shortName]/applicationPeriods/[participationId]/page.module.scss new file mode 100644 index 000000000..6ef299621 --- /dev/null +++ b/src/app/committees/[shortName]/applicationPeriods/[participationId]/page.module.scss @@ -0,0 +1,27 @@ +@use '@/styles/ohma'; +//TODO: fix styling to be aligned to the future styling pr + + +.applicationContainer { + margin-top: 1em; + display: flex; + flex-direction: column; + border: 2px solid hsla(0, 0%, 70%, 0.507); + @include ohma.round; + +} + +.headingContainer { + display: flex; + align-items: center; + + * { + display: inline-block; + margin-inline: 0.1em; + } +} + + +.applicantName { + color: black; +} \ No newline at end of file diff --git a/src/app/committees/[shortName]/applicationPeriods/[participationId]/page.tsx b/src/app/committees/[shortName]/applicationPeriods/[participationId]/page.tsx new file mode 100644 index 000000000..c4e85faf2 --- /dev/null +++ b/src/app/committees/[shortName]/applicationPeriods/[participationId]/page.tsx @@ -0,0 +1,57 @@ +import styles from './page.module.scss' +import { unwrapActionReturn } from '@/app/redirectToErrorPage' +import { readCommitteeApplicationsInPeriodAction } from '@/services/applications/committeeParticipation/actions' +import ProfilePicture from '@/components/User/ProfilePicture' +import { readSpecialImageAction } from '@/services/images/actions' +import Link from 'next/link' +import type { Image as ImageT } from '@/prisma-generated-pn-types' +export type PropTypes = { + params: Promise<{ + shortName: string, + participationId: string, + }> +} + + +async function getFallbackImageIfNoImage(image: ImageT | null) { + return image ? image : await readSpecialImageAction.bind( + null, { params: { special: 'DEFAULT_PROFILE_IMAGE' } } + )().then(res => { + if (!res.success) throw new Error('Kunne ikke finne standard profilbilde') + return res.data + }) +} + + +export default async function PeriodeCommitteePage({ params }: PropTypes) { + const participationId = parseInt((await params).participationId, 10) + const applications = unwrapActionReturn( + await readCommitteeApplicationsInPeriodAction({ params: { participationId } }) + ) + if (applications.length === 0) { return 'ingen søknader funnet' } + const sortedApplications = applications.sort((a, b) => a.priority - b.priority) + return ( +
+ {sortedApplications.map(async (application, index) => ( +
+
+

{application.priority}.

+ + +

{application.user.firstname} {application.user.lastname}

+ +
+
+

{application.text}

+
+
+ )) + } +
+ ) +} + diff --git a/src/app/committees/[shortName]/applicationPeriods/page.module.scss b/src/app/committees/[shortName]/applicationPeriods/page.module.scss new file mode 100644 index 000000000..ee12b8309 --- /dev/null +++ b/src/app/committees/[shortName]/applicationPeriods/page.module.scss @@ -0,0 +1,25 @@ +@use '@/styles/ohma'; +//TODO: fix styling to be aligned to the future styling pr + + + +.periodTable{ + border: 2px solid hsla(0, 0%, 70%, 0.507); + border-collapse: collapse; + text-align: center; + @include ohma.round; +} + + +.tableEntry { + border: 2px solid hsla(0, 0%, 70%, 0.507); + padding: 1em; +} + +.currentPeriodEntry{ + font-weight: bold; + background-color: hsla(120, 100%, 70%, 0.288); +} + +.periodHeading{} +.periodSection{} \ No newline at end of file diff --git a/src/app/committees/[shortName]/applicationPeriods/page.tsx b/src/app/committees/[shortName]/applicationPeriods/page.tsx new file mode 100644 index 000000000..9b0cd6a72 --- /dev/null +++ b/src/app/committees/[shortName]/applicationPeriods/page.tsx @@ -0,0 +1,40 @@ +import styles from './page.module.scss' +import { PeriodSection } from './periodTableSection' +import getCommittee from '@/app/committees/[shortName]/getCommittee' +import { unwrapActionReturn } from '@/app/redirectToErrorPage' +import { readCommitteeParticipatingPeriodAction } from '@/services/applications/committeeParticipation/actions' + +export type PropTypes = { + params: Promise<{ + shortName: string + }> +} + + +export default async function ApplicationPeriods({ params }: PropTypes) { + const committee = await getCommittee(params) + const shortName = (await params).shortName + const committeePeriodes = unwrapActionReturn( + await readCommitteeParticipatingPeriodAction({ params: { committeeId: committee.id } }) + ).sort((a, b) => b.startDate.getTime() - a.startDate.getTime()) + if (committeePeriodes.length === 0) { return 'ingen søknadsperioder funnet' } + return ( + + + + + + + + + + + + {committeePeriodes.map((period, index) => ( + + )) + } + +
Start datoSlutt datoOmprioritering slutt datoSøknaderSøknadstall
+ ) +} diff --git a/src/app/committees/[shortName]/applicationPeriods/periodTableSection.tsx b/src/app/committees/[shortName]/applicationPeriods/periodTableSection.tsx new file mode 100644 index 000000000..2a0791b8d --- /dev/null +++ b/src/app/committees/[shortName]/applicationPeriods/periodTableSection.tsx @@ -0,0 +1,37 @@ +'use client' //Use client to show user correct local time +import styles from './page.module.scss' +import Link from 'next/link' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faLink } from '@fortawesome/free-solid-svg-icons' +import type { readCommitteeParticipatingPeriodAction } from '@/services/applications/committeeParticipation/actions' + +export type CommitteeParticipationPeriodType = + Pick> & { success: true }, 'data'>['data'][number] + + +export function PeriodSection({ period, shortName }: { period: CommitteeParticipationPeriodType, shortName: string }) { + const entriesClassName = `${styles.tableEntry} ${period.isOpen && styles.currentPeriodEntry}` + return ( + + + {period.startDate.toLocaleDateString('en-GB')}, + kl: {period.startDate.toLocaleTimeString('en-GB')} + + + {period.endDate.toLocaleDateString('en-GB')}, + kl: {period.endDate.toLocaleTimeString('en-GB')} + + + {period.endPriorityDate.toLocaleDateString('en-GB')}, + kl: {period.endPriorityDate.toLocaleTimeString('en-GB')} + + + + + + + + {period.applicationCount} + + ) +} diff --git a/src/app/committees/[shortName]/layout.tsx b/src/app/committees/[shortName]/layout.tsx index 80ff69593..7369ea461 100644 --- a/src/app/committees/[shortName]/layout.tsx +++ b/src/app/committees/[shortName]/layout.tsx @@ -7,6 +7,7 @@ import PageWrapper from '@/components/PageWrapper/PageWrapper' import CommitteeImage from '@/components/CommitteeImage/CommitteeImage' import { committeeAuth } from '@/services/groups/committees/auth' import { ServerSession } from '@/auth/session/ServerSession' +import { committeeParticipationAuth } from '@/services/applications/committeeParticipation/auth' import type { ReactNode } from 'react' export type PropTypes = { @@ -32,6 +33,14 @@ export default async function Committee({ params, children }: PropTypes) { await ServerSession.fromNextAuth() ).toJsObject() + const canReadCommitteeApplication = committeeParticipationAuth.readAll.dynamicFields( + { + groupId: committee.groupId, + }).auth( + await ServerSession.fromNextAuth() + ).toJsObject() + + return ( <> @@ -49,7 +58,10 @@ export default async function Committee({ params, children }: PropTypes) { -