Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make org recruitment page prettier #1630

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'actual_application_deadline': timezone.now() + timezone.timedelta(days=10),
'reprioritization_deadline_for_applicant': timezone.now() + timezone.timedelta(days=11),
'reprioritization_deadline_for_groups': timezone.now() + timezone.timedelta(days=12),
'promo_media': 'x4dzJ8z1j5M',
},
{
'name_nb': 'Tidligere opptak',
Expand All @@ -23,6 +24,7 @@
'actual_application_deadline': timezone.now() - timezone.timedelta(days=50),
'reprioritization_deadline_for_applicant': timezone.now() - timezone.timedelta(days=52),
'reprioritization_deadline_for_groups': timezone.now() - timezone.timedelta(days=53),
'promo_media': 'x4dzJ8z1j5M',
},
{
'name_nb': 'Framtidig opptak',
Expand All @@ -32,6 +34,7 @@
'actual_application_deadline': timezone.now() - timezone.timedelta(days=50),
'reprioritization_deadline_for_applicant': timezone.now() - timezone.timedelta(days=52),
'reprioritization_deadline_for_groups': timezone.now() - timezone.timedelta(days=53),
'promo_media': 'x4dzJ8z1j5M',
},
]

Expand Down
15 changes: 15 additions & 0 deletions backend/root/management/commands/seed_scripts/textitems.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ def seed():
'text_nb': 'Studentersamfundet i Trondhjem er en organisasjon for studenter i Trondheim som eies og drives av sine rundt 16 100 medlemmer. Formålsparagrafen vår sier at ”Studentersamfundet skal være det naturlige samlingsstedet for studenter i Trondhjem”. Vårt røde runde huser konserter, ulike kulturarrangementer, utallige barer, en kafé og en restaurant. Mest sagnomsust er Samfundsmøtene, viet til debatt om politikk og aktuelle spørsmål, eller til underholdning og moro. Samfundet har også tre av Trondheims beste konsertscener.',
'text_en': "Samfundet is an organization for students in Trondheim that is owned and run by its approximately 16100 members. Our mission statement is Samfundet will be the natural meeting place for students in Trondheim. In our red, round building we regularly host concerts and various cultural events, and have countless bars, a café and a restaurant. The Society Meetings are perhaps our most famous events. These meetings serve as a place for debating politics and current events, and but also for entertainment and fun. Samfundet also has three of Trondheim's best music venues.",
},
{
'key': 'samf_recruitment_description',
'text_nb': 'Studentersamfundet i Trondhjem har opptak ved starten av hvert semester. Vi ønsker at du søker til oss som frivillig! Studentersamfundet i Trondhjem er Norges største studentersamfund og vi har et tilbud andre byer bare kan drømme om.',
'text_en': 'Studentersamfundet in Trondheim has recruitments at the start of each semester. We would like you to apply to us as a volunteer! Studentersamfundet in Trondheim is Norways largest student society and we have an offer that other cities can only dream of.',
},
{
'key': 'no_recruitment_samf_header',
'text_nb': 'Det er for tiden ingen opptak på Samfundet',
Expand All @@ -72,6 +77,11 @@ def seed():
'text_nb': 'Studentersamfundet i Trondhjem er Norges største studentersamfund og vi har et tilbud andre byer bare kan drømme om.',
'text_en': 'Studentersamfundet in Trondhjem is Norways largest student society and we have an offer that other cities can only dream of.',
},
{
'key': 'isfit_recruitment_description',
'text_nb': 'ISFIT har opptak ved starten av hvert semester. Vi ønsker at du søker til oss som frivillig! Som frivillig i ISFIT får du muligheten til å være med på å arrangere verdens største studentfestival.',
'text_en': 'ISFIT has recruitments at the start of each semester. We would like you to apply to us as a volunteer! As a volunteer in ISFIT, you get the opportunity to help organize the worlds largest student festival.',
},
{
'key': 'no_recruitment_isfit_header',
'text_nb': 'Det er for tiden ingen opptak på Samfundet',
Expand All @@ -87,6 +97,11 @@ def seed():
'text_nb': 'Studentersamfundet i Trondhjem er Norges største studentersamfund og vi har et tilbud andre byer bare kan drømme om.',
'text_en': 'Studentersamfundet in Trondhjem is Norways largest student society and we have an offer that other cities can only dream of.',
},
{
'key': 'uka_recruitment_description',
'text_nb': 'UKA har opptak ved starten av hvert semester. Vi ønsker at du søker til oss som frivillig! Som frivillig i UKA får du muligheten til å være med på å arrangere Norges største kulturfestival.',
'text_en': 'UKA has recruitments at the start of each semester. We would like you to apply to us as a volunteer! As a volunteer in UKA, you get the opportunity to help organize Norway\'s largest cultural festival.',
},
{
'key': 'no_recruitment_uka_header',
'text_nb': 'Det er for tiden ingen opptak på Samfundet',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
@import 'src/mixins';

.recruitmentPage {
@include flex-column-center;
@include flex-column;
padding: 2rem;

@include for-tablet-down {
padding: 1rem 0.5rem;
}
gap: 1rem;
}

.container {
@include flex-column-center;
width: 85%;
@include flex-column;
align-items: flex-start;
width: 100%;
gap: 2rem;
margin: 1rem;
}

.organizationHeader {
Expand All @@ -24,11 +30,11 @@
}

.video {
width: 50%;
width: 70%;
aspect-ratio: 16 / 9;
border: none;
@include for-tablet-down {
width: 80%;
width: 100%;
}
}

Expand All @@ -47,7 +53,9 @@
}

.optionsContainer {
@include flex-row-center;
@include flex-row;
justify-content: space-between;
align-self: stretch;
gap: 1rem;
}

Expand All @@ -74,9 +82,7 @@

.viewModeControll {
display: flex;
width: 100%;
gap: 2rem;
background-color: $grey-4;
gap: 1rem;
padding: 0.25rem;
border-radius: 0.25rem;
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import classNames from 'classnames';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import { Button, Logo, OccupiedFormModal, Page, SamfundetLogoSpinner, Text, Video } from '~/Components';
import { IconButton, Page, SamfundetLogoSpinner, Text, Video } from '~/Components';
import { PersonalRow } from '~/Pages/RecruitmentPage';
import { getOrganization, getRecruitment } from '~/api';
import { TextItem } from '~/constants';
import { useOrganizationContext } from '~/context/OrgContextProvider';
import type { RecruitmentDto } from '~/dto';
import { useDesktop, useTitle } from '~/hooks';
import { KEY } from '~/i18n/constants';
import { OrgNameType, type OrgNameTypeValue } from '~/types';
import { useDesktop, useTextItem, useTitle } from '~/hooks';
import { COLORS, OrgNameType, type OrgNameTypeValue } from '~/types';
import { dbT, getObjectFieldOrNumber } from '~/utils';
import { GangSeparatePositions, GangTypeContainer, RecruitmentTabs } from './Components';
import styles from './OrganizationRecruitmentPage.module.scss';
Expand All @@ -21,7 +20,7 @@ export function OrganizationRecruitmentPage() {
const { recruitmentId } = useParams<{ recruitmentId: string }>();
const [viewAllPositions, setViewAllPositions] = useState<boolean>(true);
const { t } = useTranslation();
const { changeOrgTheme, organizationTheme } = useOrganizationContext();
const { changeOrgTheme } = useOrganizationContext();
const [recruitment, setRecruitment] = useState<RecruitmentDto>();
const [organizationName, setOrganizationName] = useState<OrgNameTypeValue>(OrgNameType.FALLBACK);
const [loading, setLoading] = useState<boolean>(true);
Expand Down Expand Up @@ -63,72 +62,61 @@ export function OrganizationRecruitmentPage() {
}
}, [organizationName, changeOrgTheme]);

function toggleViewAll() {
const toggledValue = !viewAllPositions;
setViewAllPositions(toggledValue);
const descriptionText = (() => {
switch (organizationName) {
case OrgNameType.SAMFUNDET_NAME:
return useTextItem(TextItem.samf_recruitment_description);
case OrgNameType.UKA_NAME:
return useTextItem(TextItem.uka_recruitment_description);
case OrgNameType.ISFIT_NAME:
return useTextItem(TextItem.isfit_recruitment_description);
default:
return useTextItem(TextItem.uka_recruitment_description);
}
})();

if (loading) {
return <SamfundetLogoSpinner />;
}

return (
<Page className={styles.recruitmentPage}>
{loading ? (
<SamfundetLogoSpinner />
) : (
<div className={styles.container}>
<div className={styles.organizationHeader} style={{ backgroundColor: organizationTheme?.pagePrimaryColor }}>
<Logo organization={organizationName} color="light" size={isDesktop ? 'small' : 'xsmall'} />
<Text as="strong" size={isDesktop ? 'xl' : 'l'}>
{dbT(recruitment, 'name')}
</Text>
</div>
{recruitment?.promo_media && <Video embedId={recruitment.promo_media} className={styles.video} />}
<div
className={classNames(
organizationName === 'Samfundet' && styles.samfRecruitmentSubHeader,
organizationName === 'UKA' && styles.ukaRecruitmentSubHeader,
organizationName === 'ISFiT' && styles.isfitRecruitmentSubHeader,
styles.basicRecruitmentSubHeader,
)}
>
<Text as={'strong'} size={isDesktop ? 'xl' : 'l'}>
{t(KEY.recruitment_apply_for)} {organizationName}
</Text>
</div>
<div className={styles.personalRow}>
{recruitmentId && (
<>
<OccupiedFormModal recruitmentId={+recruitmentId} />
<PersonalRow
recruitmentId={recruitmentId}
organizationName={organizationName}
showRecruitmentBtn={false}
/>
</>
)}
</div>
<div className={styles.openPositionsWrapper}>
<div className={styles.optionsContainer}>
<div className={styles.viewModeControll}>
<Button
theme={positionsViewMode === 'list' ? 'selected' : 'outlined'}
onClick={() => setViewMode('list')}
>
{t(KEY.common_list_view)}
</Button>
<Button
theme={positionsViewMode === 'tab' ? 'selected' : 'outlined'}
onClick={() => setViewMode('tab')}
>
{t(KEY.common_tab_view)}
</Button>
</div>
</div>
{recruitmentId && (positionsViewMode === 'list' ? <GangTypeContainer /> : <RecruitmentTabs />)}
{recruitment?.separate_positions && recruitment.separate_positions.length > 0 && (
<GangSeparatePositions recruitmentSeparatePositions={recruitment.separate_positions} />
)}
<div className={styles.container}>
<Text as="strong" size={isDesktop ? 'xl' : 'l'}>
{dbT(recruitment, 'name')}
</Text>
{recruitment?.promo_media && <Video embedId={recruitment.promo_media} className={styles.video} />}

<Text as={'strong'} size={'m'}>
{descriptionText}
</Text>
</div>
<div className={styles.openPositionsWrapper}>
<div className={styles.optionsContainer}>
{recruitmentId && (
<PersonalRow recruitmentId={recruitmentId} organizationName={organizationName} showRecruitmentBtn={false} />
)}
<div className={styles.viewModeControll}>
<IconButton
title=""
color={positionsViewMode === 'list' ? COLORS.black : COLORS.grey_35}
avatarColor={positionsViewMode === 'list' ? COLORS.white : COLORS.white}
onClick={() => setViewMode('list')}
icon={'material-symbols:view-list'}
/>
<IconButton
title=""
color={positionsViewMode === 'tab' ? COLORS.black : COLORS.grey_35}
onClick={() => setViewMode('tab')}
icon={'material-symbols:tabs-outline-rounded'}
/>
</div>
</div>
)}
{recruitmentId && (positionsViewMode === 'list' ? <GangTypeContainer /> : <RecruitmentTabs />)}
{recruitment?.separate_positions && recruitment.separate_positions.length > 0 && (
<GangSeparatePositions recruitmentSeparatePositions={recruitment.separate_positions} />
)}
</div>
</Page>
);
}
3 changes: 3 additions & 0 deletions frontend/src/constants/TextItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,19 @@ export const TextItem = {
sulten_contact_page_title: 'sulten_contact_page_title',

//Recruitment samf
samf_recruitment_description: 'samf_recruitment_description',
no_recruitment_samf_header: 'no_recruitment_samf_header',
no_recruitment_samf_about: 'no_recruitment_samf_about',
no_recruitment_samf_next: 'no_recruitment_samf_next',

//Recruitment ISFIT
isfit_recruitment_description: 'isfit_recruitment_description',
no_recruitment_isfit_header: 'no_recruitment_isfit_header',
no_recruitment_isfit_about: 'no_recruitment_isfit_about',
no_recruitment_isfit_next: 'no_recruitment_isfit_next',

//Recruitment UKA
uka_recruitment_description: 'uka_recruitment_description',
no_recruitment_uka_header: 'no_recruitment_uka_header',
no_recruitment_uka_about: 'no_recruitment_uka_about',
no_recruitment_uka_next: 'no_recruitment_uka_next',
Expand Down
14 changes: 9 additions & 5 deletions frontend/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,20 @@ export function useMobile(): boolean {
/**
* Hook that returns the correct translation for given key
*/
export function useTextItem(key: TextItemValue, language?: string): string | undefined {
export function useTextItem(key: TextItemValue, language?: string): string {
const [textItem, setTextItem] = useState<TextItemDto>();
const { i18n } = useTranslation();
const isNorwegian = (language || i18n.language) === LANGUAGES.NB;
useEffect(() => {
getTextItem(key).then((data) => {
setTextItem(data);
});
getTextItem(key)
.then((data) => {
setTextItem(data);
})
.catch(() => {
setTextItem(undefined);
});
}, [key]);
return isNorwegian ? textItem?.text_nb : textItem?.text_en;
return isNorwegian ? textItem?.text_nb || '' : textItem?.text_en || '';
}

/**
Expand Down
Loading