Skip to content

Commit

Permalink
Remove the use of getOrganization (#1628)
Browse files Browse the repository at this point in the history
* remove unecessary extra calls to organization

* fixes

* fixups

* biome fix

---------

Co-authored-by: magsyg <[email protected]>
  • Loading branch information
magsyg and magsyg authored Dec 16, 2024
1 parent 5cd8ee9 commit 2d28bf5
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,40 @@ import { useTranslation } from 'react-i18next';
import { useParams } from 'react-router-dom';
import { Button, Logo, OccupiedFormModal, Page, SamfundetLogoSpinner, Text, Video } from '~/Components';
import { PersonalRow } from '~/Pages/RecruitmentPage';
import { getOrganization, getRecruitment } from '~/api';
import { getRecruitment } from '~/api';
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 { dbT, getObjectFieldOrNumber } from '~/utils';
import { dbT } from '~/utils';
import { GangSeparatePositions, GangTypeContainer, RecruitmentTabs } from './Components';
import styles from './OrganizationRecruitmentPage.module.scss';

type ViewMode = 'list' | 'tab';

const ORG_STYLES = {
[OrgNameType.SAMFUNDET_NAME]: {
subHeaderStyle: styles.samfRecruitmentSubHeader,
},
[OrgNameType.UKA_NAME]: {
subHeaderStyle: styles.ukaRecruitmentSubHeader,
},
[OrgNameType.ISFIT_NAME]: {
subHeaderStyle: styles.isfitRecruitmentSubHeader,
},
[OrgNameType.FALLBACK]: {
subHeaderStyle: '',
},
};

export function OrganizationRecruitmentPage() {
const isDesktop = useDesktop();
const { recruitmentId } = useParams<{ recruitmentId: string }>();
const [viewAllPositions, setViewAllPositions] = useState<boolean>(true);
const { t } = useTranslation();
const { changeOrgTheme, organizationTheme } = useOrganizationContext();
const [recruitment, setRecruitment] = useState<RecruitmentDto>();
const [organizationName, setOrganizationName] = useState<OrgNameTypeValue>(OrgNameType.FALLBACK);
const [loading, setLoading] = useState<boolean>(true);
const [positionsViewMode, setViewMode] = useState<ViewMode>('list');

Expand All @@ -43,25 +57,10 @@ export function OrganizationRecruitmentPage() {

useEffect(() => {
if (recruitment) {
getOrganization(getObjectFieldOrNumber<number>(recruitment.organization, 'id'))
.then((response) => {
if (Object.values(OrgNameType).includes(response.name as OrgNameTypeValue)) {
setOrganizationName(response.name as OrgNameTypeValue);
}
})
.catch((error) => {
console.log(error);
setOrganizationName(OrgNameType.FALLBACK);
});
changeOrgTheme(recruitment.organization.name as OrgNameTypeValue);
}
setLoading(false);
}, [recruitment]);

useEffect(() => {
if (organizationName) {
changeOrgTheme(organizationName);
}
}, [organizationName, changeOrgTheme]);
}, [recruitment, changeOrgTheme]);

function toggleViewAll() {
const toggledValue = !viewAllPositions;
Expand All @@ -75,22 +74,24 @@ export function OrganizationRecruitmentPage() {
) : (
<div className={styles.container}>
<div className={styles.organizationHeader} style={{ backgroundColor: organizationTheme?.pagePrimaryColor }}>
<Logo organization={organizationName} color="light" size={isDesktop ? 'small' : 'xsmall'} />
<Logo
organization={(recruitment?.organization.name as OrgNameTypeValue) ?? OrgNameType.FALLBACK}
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,
ORG_STYLES[(recruitment?.organization.name as OrgNameTypeValue) ?? OrgNameType.FALLBACK].subHeaderStyle,
styles.basicRecruitmentSubHeader,
)}
>
<Text as={'strong'} size={isDesktop ? 'xl' : 'l'}>
{t(KEY.recruitment_apply_for)} {organizationName}
{t(KEY.recruitment_apply_for)} {recruitment?.organization.name}
</Text>
</div>
<div className={styles.personalRow}>
Expand All @@ -99,7 +100,7 @@ export function OrganizationRecruitmentPage() {
<OccupiedFormModal recruitmentId={+recruitmentId} />
<PersonalRow
recruitmentId={recruitmentId}
organizationName={organizationName}
organizationName={recruitment?.organization.name}
showRecruitmentBtn={false}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { ROUTES } from '~/routes';

type PersonalRowProps = {
recruitmentId: string;
organizationName: string;
organizationName?: string;
showRecruitmentBtn?: boolean;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,16 @@
import { t } from 'i18next';
import { useEffect, useState } from 'react';
import { Logo, SamfundetLogoSpinner, TimeDisplay } from '~/Components';
import { Logo, TimeDisplay } from '~/Components';
import { Text } from '~/Components/Text/Text';
import { PersonalRow } from '~/Pages/RecruitmentPage/Components/PersonalRow/PersonalRow';
import { getOrganization } from '~/api';
import type { RecruitmentDto } from '~/dto';
import { useDesktop, useIsDarkTheme } from '~/hooks';
import { KEY } from '~/i18n/constants';
import { OrgNameType, type OrgNameTypeValue } from '~/types';
import { dbT } from '~/utils';
import styles from './RecruitmentCard.module.scss';

type RecruitmentCardProps = {
recruitment_id?: string;
recruitment_name?: string;
shown_application_deadline?: string;
reprioritization_deadline_for_applicant?: string;
organization_id: number;
isAuthenticated?: boolean;
recruitment: RecruitmentDto;
};

const CARD_STYLE = {
Expand All @@ -33,37 +28,13 @@ const CARD_STYLE = {
},
};

export function RecruitmentCard({
recruitment_id = '-1',
recruitment_name = 'N/A',
shown_application_deadline = 'N/A',
reprioritization_deadline_for_applicant = 'N/A',
organization_id,
}: RecruitmentCardProps) {
export function RecruitmentCard({ recruitment }: RecruitmentCardProps) {
const isDesktop = useDesktop();
const isDarkTheme = useIsDarkTheme();
const [organizationName, setOrganizationName] = useState<OrgNameTypeValue>(OrgNameType.FALLBACK);
const [loading, setLoading] = useState<boolean>(true);

useEffect(() => {
getOrganization(organization_id)
.then((response) => {
if (Object.values(OrgNameType).includes(response.name as OrgNameTypeValue)) {
setOrganizationName(response.name as OrgNameTypeValue);
} else {
setOrganizationName(OrgNameType.FALLBACK);
}
})
.catch((error) => {
console.log(error);
setOrganizationName(OrgNameType.FALLBACK);
});
setLoading(false);
}, [organization_id]);

const cardHeaderText = (
<Text size={isDesktop ? 'l' : 'm'} as="strong">
{recruitment_name}
{dbT(recruitment, 'name')}
</Text>
);

Expand All @@ -73,53 +44,62 @@ export function RecruitmentCard({
<Text size="m" as="strong">
{t(KEY.recruitment_organization)}
</Text>
{organizationName}
{recruitment.organization.name}
</Text>
<Text size="m" as="p">
<Text size="m" as="strong">
{t(KEY.application_deadline)}:
</Text>
<TimeDisplay timestamp={shown_application_deadline} displayType="nice-date" className={styles.timeDisplay} />
<TimeDisplay
timestamp={recruitment.shown_application_deadline}
displayType="nice-date"
className={styles.timeDisplay}
/>
{', '}
<TimeDisplay timestamp={shown_application_deadline} displayType="time" className={styles.timeDisplay} />
<TimeDisplay
timestamp={recruitment.shown_application_deadline}
displayType="time"
className={styles.timeDisplay}
/>
</Text>
<Text size="m" as="p">
<Text size="m" as="strong">
{t(KEY.reprioritization_deadline_for_applicant)}:
</Text>
<TimeDisplay
timestamp={reprioritization_deadline_for_applicant}
timestamp={recruitment.reprioritization_deadline_for_applicant}
displayType="nice-date"
className={styles.timeDisplay}
/>
{', '}
<TimeDisplay
timestamp={reprioritization_deadline_for_applicant}
timestamp={recruitment.reprioritization_deadline_for_applicant}
displayType="time"
className={styles.timeDisplay}
/>
</Text>
</>
);

return loading ? (
<SamfundetLogoSpinner />
) : (
<div key={recruitment_id} className={CARD_STYLE[organizationName].orgStyle}>
return recruitment.id ? (
<div key={recruitment.id} className={CARD_STYLE[recruitment.organization.name as OrgNameTypeValue].orgStyle}>
<div className={styles.cardHeader}>{cardHeaderText}</div>
<div className={styles.cardText}>{cardContentText}</div>
<div className={styles.cardLogo}>
{organizationName && (
<Logo
color={isDarkTheme ? 'light' : 'org-color'}
organization={organizationName}
size={isDesktop ? 'small' : 'xsmall'}
/>
)}
<Logo
color={isDarkTheme ? 'light' : 'org-color'}
organization={recruitment.organization.name as OrgNameTypeValue}
size={isDesktop ? 'small' : 'xsmall'}
/>
</div>
<div className={styles.personalRow}>
<PersonalRow recruitmentId={recruitment_id} organizationName={organizationName} />
<PersonalRow
recruitmentId={recruitment.id}
organizationName={recruitment.organization.name as OrgNameTypeValue}
/>
</div>
</div>
) : (
<></>
);
}
10 changes: 1 addition & 9 deletions frontend/src/Pages/RecruitmentPage/RecruitmentPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { getActiveRecruitments } from '~/api';
import type { RecruitmentDto } from '~/dto';
import { useTitle } from '~/hooks';
import { KEY } from '~/i18n/constants';
import { dbT, getObjectFieldOrNumber } from '~/utils';
import { NoPositions, RecruitmentCard } from './Components';
import styles from './RecruitmentPage.module.scss';

Expand Down Expand Up @@ -34,14 +33,7 @@ export function RecruitmentPage() {
<SamfundetLogoSpinner />
) : recruitments && recruitments.length > 0 ? (
recruitments.map((recruitment: RecruitmentDto) => (
<RecruitmentCard
key={recruitment.id}
recruitment_id={recruitment.id}
recruitment_name={dbT(recruitment, 'name')}
shown_application_deadline={recruitment.shown_application_deadline}
reprioritization_deadline_for_applicant={recruitment.reprioritization_deadline_for_applicant}
organization_id={getObjectFieldOrNumber<number>(recruitment.organization, 'id') ?? 0}
/>
<RecruitmentCard recruitment={recruitment} key={recruitment.id} />
))
) : (
<NoPositions />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import type { DropdownOption } from '~/Components/Dropdown/Dropdown';
import { FormDescription } from '~/Components/Forms/Form';
import { getOrganizations, postRecruitment, putRecruitment } from '~/api';
import type { OrganizationDto, RecruitmentDto } from '~/dto';
import type { OrganizationDto, RecruitmentWriteDto } from '~/dto';
import { useTitle } from '~/hooks';
import { KEY } from '~/i18n/constants';
import type { RecruitmentLoader } from '~/router/loaders';
Expand Down Expand Up @@ -77,7 +77,7 @@ export function RecruitmentFormAdminPage() {

function onSubmit(data: recruitmentFormType) {
if (recruitmentId) {
putRecruitment(recruitmentId, data as RecruitmentDto)
putRecruitment(recruitmentId, data as RecruitmentWriteDto)
.then(() => {
toast.success(t(KEY.common_update_successful));
navigate(ROUTES.frontend.admin_recruitment);
Expand All @@ -86,7 +86,7 @@ export function RecruitmentFormAdminPage() {
toast.error(t(KEY.common_something_went_wrong));
});
} else {
postRecruitment(data as RecruitmentDto)
postRecruitment(data as RecruitmentWriteDto)
.then(() => {
toast.success(t(KEY.common_creation_successful));
navigate(ROUTES.frontend.admin_recruitment);
Expand Down
5 changes: 3 additions & 2 deletions frontend/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import type {
RecruitmentStatsDto,
RecruitmentUnprocessedApplicationsDto,
RecruitmentUserDto,
RecruitmentWriteDto,
RegistrationDto,
RoleDto,
RoleUsersDto,
Expand Down Expand Up @@ -549,14 +550,14 @@ export async function getRecruitment(id: string): Promise<AxiosResponse<Recruitm
return response;
}

export async function postRecruitment(recruitmentData: RecruitmentDto): Promise<AxiosResponse> {
export async function postRecruitment(recruitmentData: RecruitmentWriteDto): Promise<AxiosResponse> {
const url = BACKEND_DOMAIN + ROUTES.backend.samfundet__recruitment_list;
const response = await axios.post(url, recruitmentData, { withCredentials: true });

return response;
}

export async function putRecruitment(id: string, recruitment: Partial<RecruitmentDto>): Promise<AxiosResponse> {
export async function putRecruitment(id: string, recruitment: Partial<RecruitmentWriteDto>): Promise<AxiosResponse> {
const url =
BACKEND_DOMAIN + reverse({ pattern: ROUTES.backend.samfundet__recruitment_detail, urlParams: { pk: id } });
const response = await axios.put<RecruitmentDto>(url, recruitment, { withCredentials: true });
Expand Down
6 changes: 5 additions & 1 deletion frontend/src/dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,12 +424,16 @@ export type RecruitmentDto = {
reprioritization_deadline_for_applicant: string;
reprioritization_deadline_for_groups: string;
max_applications?: number;
organization: number | OrganizationDto;
organization: OrganizationDto;
separate_positions?: RecruitmentSeparatePositionDto[];
recruitment_progress?: number;
promo_media?: string;
};

export type RecruitmentWriteDto = RecruitmentDto & {
organization: number;
};

export type RecruitmentSeparatePositionDto = {
id?: number;
name_nb: string;
Expand Down

0 comments on commit 2d28bf5

Please sign in to comment.