Skip to content

Commit

Permalink
feat(JobOffer): Job offet list (#17)
Browse files Browse the repository at this point in the history
* feat(JobOffer): Job offet list

* refactor: fix some nits

* feat: rework job offers styles

---------

Co-authored-by: Kuruyia <[email protected]>
  • Loading branch information
thomas-mauran and Kuruyia authored Nov 26, 2023
1 parent 63f3437 commit 26ef084
Show file tree
Hide file tree
Showing 13 changed files with 325 additions and 6 deletions.
5 changes: 5 additions & 0 deletions front/assets/translations/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
"cancel": "Cancel",
"delete": "Delete"
},
"jobOffer": {
"info": {
"jobOffer": "Job offer"
}
},
"profile": {
"info": {
"contact": "Contact",
Expand Down
5 changes: 5 additions & 0 deletions front/assets/translations/fr_FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
"cancel": "Annuler",
"delete": "Supprimer"
},
"jobOffer": {
"info": {
"jobOffer": "Offre d'emploi"
}
},
"profile": {
"info": {
"contact": "Contact",
Expand Down
8 changes: 4 additions & 4 deletions front/package-lock.json

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

2 changes: 1 addition & 1 deletion front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"typescript:check": "tsc --noEmit"
},
"dependencies": {
"@react-native-community/slider": "^4.4.3",
"@react-native-community/slider": "4.4.2",
"@react-navigation/material-top-tabs": "^6.6.5",
"@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.16",
Expand Down
80 changes: 80 additions & 0 deletions front/src/components/jobOffers/JobOfferItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { useLocales } from 'expo-localization';
import { FC } from 'react';
import { StyleSheet, View } from 'react-native';
import { Text, useTheme } from 'react-native-paper';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';

import { JobOffer } from '@/models/entities/jobOffer';

/**
* The styles for the JobOfferItem component.
*/
const styles = StyleSheet.create({
container: {
gap: 16,
},
horizontalContainer: {
flexDirection: 'row',
gap: 12,
},
sectionContainer: {
gap: 8,
},
});

/**
* The props for the JobOfferItem component.
*/
type JobOfferItemProps = {
/**
* The job offer to display.
*/
jobOffer: JobOffer;
};

/**
* Displays a job offer.
* @constructor
*/
const JobOfferItem: FC<JobOfferItemProps> = ({ jobOffer }) => {
// Hooks
const locales = useLocales();
const theme = useTheme();

return (
<View style={styles.container}>
<View style={styles.sectionContainer}>
<Text variant='titleLarge'>{`${jobOffer.title}`}</Text>
<Text>{`${jobOffer.description}`}</Text>
</View>

<View style={styles.sectionContainer}>
<View style={styles.horizontalContainer}>
<MaterialCommunityIcons
name='calendar'
size={24}
style={{ color: theme.colors.onSurface }}
/>
<Text variant='labelLarge'>
{`${new Date(jobOffer.startDate).toLocaleDateString(
locales[0].languageTag,
)} - ${new Date(jobOffer.endDate).toLocaleDateString(
locales[0].languageTag,
)}`}
</Text>
</View>

<View style={styles.horizontalContainer}>
<MaterialCommunityIcons
name='map-marker'
size={24}
style={{ color: theme.colors.onSurface }}
/>
<Text variant='labelLarge'>{`${jobOffer.geographicArea}`}</Text>
</View>
</View>
</View>
);
};

export default JobOfferItem;
47 changes: 47 additions & 0 deletions front/src/components/jobOffers/JobOfferList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { FC } from 'react';
import { StyleSheet, View } from 'react-native';
import { Divider } from 'react-native-paper';

import { JobOffer } from '@/models/entities/jobOffer';

import JobOfferItem from './JobOfferItem';

/**
* The styles for the JobOfferList component.
*/
const styles = StyleSheet.create({
divider: {
height: 1,
marginVertical: 8,
width: '100%',
},
});

/**
* The props for the JobOfferList component.
*/
type JobOfferProps = {
/**
* The job offers to display.
*/
jobOffers: JobOffer[];
};

/**
* Displays a list of job offers.
* @constructor
*/
const JobOfferList: FC<JobOfferProps> = ({ jobOffers }) => {
return (
<View>
{jobOffers?.map((jobOffer) => (
<View key={jobOffer.id}>
<JobOfferItem jobOffer={jobOffer} />
<Divider style={styles.divider} />
</View>
))}
</View>
);
};

export default JobOfferList;
51 changes: 51 additions & 0 deletions front/src/models/entities/jobOffer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* The status of a job offer.
*/
export enum JobOfferStatus {
NOT_APPLIED = -1,
APPLIED = 0,
ACCEPTED = 1,
REJECTED = 2,
}

/**
* A job offer.
*/
export type JobOffer = {
/**
* The id of the job offer.
*/
id: string;

/**
* The title of the job offer.
*/
title: string;

/**
* The description of the job offer.
*/
description: string;

/**
* The start date of the job offer.
* Formatted as an ISO 8601 string.
*/
startDate: string;

/**
* The end date of the job offer.
* Formatted as an ISO 8601 string.
*/
endDate: string;

/**
* The geographic area of the job offer.
*/
geographicArea: string;

/**
* The status of the job offer.
*/
status: JobOfferStatus;
};
8 changes: 8 additions & 0 deletions front/src/pages/internal/InternalPagesNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import PaperNavigationBar from '@/components/utils/PaperNavigationBar';
import InternalPagesPage from '@/pages/internal/InternalPagesPage';
import ProfileNav from '@/pages/profile/ProfileNav';

import JobOffersNav from '../jobOffer/JobOfferNav';

/**
* The parameter list for the InternalPagesNav navigator.
*/
export type InternalPagesStackParamList = {
PagesMain: undefined;
PagesProfile: undefined;
PagesJobOffer: undefined;
};

const InternalPagesStack =
Expand All @@ -35,6 +38,11 @@ const InternalPagesNav = () => {
component={ProfileNav}
options={{ headerShown: false }}
/>
<InternalPagesStack.Screen
name='PagesJobOffer'
component={JobOffersNav}
options={{ headerShown: false }}
/>
</InternalPagesStack.Navigator>
);
};
Expand Down
7 changes: 7 additions & 0 deletions front/src/pages/internal/InternalPagesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ const InternalPagesPage: FC<InternalPagesPageProps> = ({ navigation }) => {
navigation.navigate('PagesProfile');
}, [navigation]);

const handleJobOfferPress = useCallback(() => {
navigation.navigate('PagesJobOffer');
}, [navigation]);

return (
<ScrollView
style={styles.container}
Expand All @@ -42,6 +46,9 @@ const InternalPagesPage: FC<InternalPagesPageProps> = ({ navigation }) => {
<Button mode={'contained'} onPress={handleProfilePress}>
Profile
</Button>
<Button mode={'contained'} onPress={handleJobOfferPress}>
JobOffer
</Button>
</ScrollView>
);
};
Expand Down
35 changes: 35 additions & 0 deletions front/src/pages/jobOffer/JobOfferNav.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { createNativeStackNavigator } from '@react-navigation/native-stack';

import PaperNavigationBar from '@/components/utils/PaperNavigationBar';
import JobOfferPage from '@/pages/jobOffer/JobOfferPage';
import i18n from '@/utils/i18n';

/**
* The parameter list for the JobOffersNav navigator.
*/
export type JobOfferStackParamList = {
JobOffer: undefined;
};

const JobOfferStack = createNativeStackNavigator<JobOfferStackParamList>();

/**
* The stack navigator for the job offers pages.
* @constructor
*/
const JobOffersNav = () => {
return (
<JobOfferStack.Navigator
initialRouteName='JobOffer'
screenOptions={{ header: (props) => <PaperNavigationBar {...props} /> }}
>
<JobOfferStack.Screen
name='JobOffer'
component={JobOfferPage}
options={{ headerTitle: `${i18n.t('jobOffer.info.jobOffer')}` }}
/>
</JobOfferStack.Navigator>
);
};

export default JobOffersNav;
62 changes: 62 additions & 0 deletions front/src/pages/jobOffer/JobOfferPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { useFocusEffect } from '@react-navigation/native';
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import { FC, useCallback } from 'react';
import { ScrollView, StyleSheet } from 'react-native';

import JobOfferList from '@/components/jobOffers/JobOfferList';
import { useGetJobOffersQuery } from '@/store/api/jobApiSlice';

import { JobOfferStackParamList } from './JobOfferNav';

/**
* The styles for the JobOfferPage component.
*/
const styles = StyleSheet.create({
container: {
flex: 1,
},
contentContainer: {
gap: 8,
paddingBottom: 8,
paddingHorizontal: 16,
},
});

/**
* The props for the JobOfferPage component.
*/
type JobOfferPageProps = NativeStackScreenProps<
JobOfferStackParamList,
'JobOffer'
>;

/**
* Displays the page of job offers for the current user.
* @constructor
*/
const JobOfferPage: FC<JobOfferPageProps> = () => {
// API calls
const { data: jobOffers, refetch: refetchJobOffers } = useGetJobOffersQuery();

// Fetch data from the API when the page is focused
useFocusEffect(
useCallback(() => {
refetchJobOffers();
}, [refetchJobOffers]),
);

if (jobOffers === undefined) {
return null;
}

return (
<ScrollView
style={styles.container}
contentContainerStyle={styles.contentContainer}
>
<JobOfferList jobOffers={jobOffers} />
</ScrollView>
);
};

export default JobOfferPage;
1 change: 1 addition & 0 deletions front/src/store/api/apiSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ export const apiSlice = createApi({
'Profile',
'References',
'Job',
'JobOffer',
],
});
Loading

0 comments on commit 26ef084

Please sign in to comment.