Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
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
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