Skip to content
Open
39 changes: 0 additions & 39 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 11 additions & 5 deletions src/app/committees/[shortName]/Nav.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
'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}/periodes`
const membersPath = `/committees/${shortName}/members`
const aboutPath = `/committees/${shortName}/about`

return (
<SubPageNavBar>
<SubPageNavBarItem icon={faCog} href={settingsPath}>Innstillinger</SubPageNavBarItem>
<SubPageNavBarItem icon={faCog} href={adminPath}>Innstillinger</SubPageNavBarItem>
{canReadCommitteeApplication.authorized &&
<SubPageNavBarItem icon={faScroll} href={readPeriodesPath}>Perioder</SubPageNavBarItem>
}
<SubPageNavBarItem icon={faUsers} href={membersPath}>Members</SubPageNavBarItem>
<SubPageNavBarItem icon={faInfo} href={aboutPath}>About</SubPageNavBarItem>
<SubPageNavBarItem icon={faArrowLeft} href={
Expand Down
14 changes: 13 additions & 1 deletion src/app/committees/[shortName]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand All @@ -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 (
<>
<BackdropImage image={committeeLogo}>
Expand All @@ -49,7 +58,10 @@ export default async function Committee({ params, children }: PropTypes) {
</div>
</PageWrapper>
</BackdropImage>
<Nav shortName={(await params).shortName} />
<Nav
shortName={(await params).shortName}
canReadCommitteeApplication={canReadCommitteeApplication}
/>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
@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;
}

.applicationsContainer {}
Comment thread
HaakonMikalsen marked this conversation as resolved.
Outdated
.profilePicture {}
.applicationTextContainer {}
.applicationText {}
57 changes: 57 additions & 0 deletions src/app/committees/[shortName]/periodes/[participationId]/page.tsx
Original file line number Diff line number Diff line change
@@ -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 loadUserImage(image: ImageT | null) {
Comment thread
HaakonMikalsen marked this conversation as resolved.
Outdated
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.applicationPriority - b.applicationPriority)
return (
<div className={styles.applicationsContainer}>
{sortedApplications.map(async (application, index) => (
<div className={styles.applicationContainer} key={index}>
<div className={styles.headingContainer}>
<h3>{application.applicationPriority}.</h3>
<ProfilePicture
width={50}
profileImage={(await loadUserImage(application.image))}
className={styles.profilePicture}
/>
<Link className={styles.applicantName} href={`/users/${application.username}`}>
<h3>{application.firstname} {application.lastname}</h3>
</Link>
</div>
<div className={styles.applicationTextContainer}>
<p className={styles.applicationText}>{application.applicationText}</p>
</div>
</div >
))
}
</div >
)
}

25 changes: 25 additions & 0 deletions src/app/committees/[shortName]/periodes/page.module.scss
Original file line number Diff line number Diff line change
@@ -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{}
36 changes: 36 additions & 0 deletions src/app/committees/[shortName]/periodes/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
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 PeriodeCommitteePage({ params }: PropTypes) {
Comment thread
HaakonMikalsen marked this conversation as resolved.
Outdated
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 (
<table className={styles.periodTable}>
<tr className={styles.periodHeading}>
<th className={styles.tableEntry}>Start dato</th>
<th className={styles.tableEntry}>Slutt dato</th>
<th className={styles.tableEntry}>Omprioritering slutt dato</th>
<th className={styles.tableEntry}>Søknader</th>
<th className={styles.tableEntry}>Søknadstall</th>
</tr>
{committeePeriodes.map((period, index) => (
<PeriodSection shortName={shortName} key={index} period={period}></PeriodSection>
))
}
</table >
)
}
42 changes: 42 additions & 0 deletions src/app/committees/[shortName]/periodes/periodTableSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use client' //Use client to show user correct local time
import styles from './page.module.scss'
import { useState } from 'react'
import Link from 'next/link'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faLink } from '@fortawesome/free-solid-svg-icons'

type periodType = {
participationId: number;
applicationCount: number;
startDate: Date;
endDate: Date;
endPriorityDate: Date;
}

export function PeriodSection({ period, shortName }: { period: periodType, shortName: string }) {
const [now] = useState(() => Date.now())
Comment thread
HaakonMikalsen marked this conversation as resolved.
Outdated
const isCurrentPeriod = (now > period.startDate.getTime()) && (now < period.endPriorityDate.getTime())
const entriesClassName = `${styles.tableEntry} ${isCurrentPeriod && styles.currentPeriodEntry}`
return (
<tr className={styles.periodSection}>
<td className={entriesClassName} >
{period.startDate.toLocaleDateString('en-GB')},
kl: {period.startDate.toLocaleTimeString('en-GB')}
</td>
<td className={entriesClassName} >
{period.endDate.toLocaleDateString('en-GB')},
kl: {period.endDate.toLocaleTimeString('en-GB')}
</td>
<td className={entriesClassName} >
{period.endPriorityDate.toLocaleDateString('en-GB')},
kl: {period.endPriorityDate.toLocaleTimeString('en-GB')}
</td>
<td className={entriesClassName} > <Link href={`/committees/${shortName}/periodes/${period.participationId}`} >
<FontAwesomeIcon icon={faLink}>
</FontAwesomeIcon>
</Link>
</td>
<td className={entriesClassName} >{period.applicationCount}</td>
</tr>
)
}
Loading
Loading