diff --git a/studentbyer/App.tsx b/studentbyer/App.tsx index b0cb8b2895ba3eb39bdf7e868fa052a18db7e1ae..ae6efe898de10eb4b260d3ed8bf305065f173b7c 100644 --- a/studentbyer/App.tsx +++ b/studentbyer/App.tsx @@ -1,4 +1,3 @@ -import { StatusBar } from "expo-status-bar"; import React from "react"; import "react-native-gesture-handler"; import useCachedResources from "./hooks/useCachedResources"; @@ -9,25 +8,34 @@ import { createStackNavigator } from "@react-navigation/stack"; import { SearchScreen } from "./screens/SearchScreen"; import StudentCityScreen from "./screens/StudentCityScreen"; import AddReviewScreen from "./screens/AddReviewScreen"; -import { Animated, Easing } from "react-native"; import { TransitionSpec } from "@react-navigation/stack/lib/typescript/src/types"; -import { StyleSheet, Button, KeyboardAvoidingView } from "react-native"; -import { Platform } from "react-native"; import { SafeAreaProvider } from "react-native-safe-area-context"; import { HomeScreen } from "./screens/HomeScreen"; -const Stack = createStackNavigator(); +// Needed to make navigation typed, see: https://reactnavigation.org/docs/typescript/ +export type StackParamList = { + Home: undefined; + Search: undefined; + StudentCity: undefined; + AddReview: undefined; +}; + +const Stack = createStackNavigator<StackParamList>(); -/* This animation sets duration to 0, we had an issue with the screen flashing white for a short duration. -This is probably due to duration being set to a small amount automatically if not overriden */ +/* This animation sets duration to 10, we had an issue with the screen flashing white for a short duration. +This is probably due to duration being set to a small amount (over the screens refresh-rate) */ const config: TransitionSpec = { animation: "timing", config: { duration: 10, }, }; + +/* + * Main app + */ export default function App() { - const isLoadingComplete = useCachedResources(); + const isLoadingComplete = useCachedResources(); // Loads all data we need from cached resources if (!isLoadingComplete) { return null; @@ -45,7 +53,7 @@ export default function App() { name="Home" component={HomeScreen} options={{ - transitionSpec: { open: config, close: config }, + transitionSpec: { open: config, close: config }, // Adding transition animations }} /> <Stack.Screen diff --git a/studentbyer/components/AddRating/AddStarRating/index.tsx b/studentbyer/components/AddRating/AddStarRating/index.tsx index 2548a8f58afd0b78516467f885596d82e866bb38..b5e0762f18f1632087e5ee1562d5116a60dca873 100644 --- a/studentbyer/components/AddRating/AddStarRating/index.tsx +++ b/studentbyer/components/AddRating/AddStarRating/index.tsx @@ -2,10 +2,13 @@ import * as React from "react"; import Icon from "react-native-vector-icons/FontAwesome5"; import { View } from "react-native"; +/* + * Component which renders 5 clickable stars + */ const AddStarRating = ({ onPress, rating, - size + size, }: { onPress: (number: number) => void; rating: number; @@ -14,7 +17,7 @@ const AddStarRating = ({ const array = [1, 2, 3, 4, 5]; return ( <View style={{ flex: 1, flexDirection: "row" }}> - {array.map(number => { + {array.map((number) => { if (number <= rating) { return ( <Icon diff --git a/studentbyer/components/AddRating/index.tsx b/studentbyer/components/AddRating/index.tsx index 75948699e40f0464b5eb74e4c1e2ab00c65946e4..c252d0462094960a74dd942ad071b03c8549d791 100644 --- a/studentbyer/components/AddRating/index.tsx +++ b/studentbyer/components/AddRating/index.tsx @@ -2,10 +2,13 @@ import * as React from "react"; import { View, Text } from "react-native"; import AddStarRating from "./AddStarRating"; +/* + * Component for adding rating to a value, for example "Vurdering pris" + */ const AddRating = ({ rating, text, - setRating + setRating, }: { rating: number; text: String; @@ -17,7 +20,7 @@ const AddRating = ({ flex: 5, flexDirection: "column", justifyContent: "center", - alignItems: "center" + alignItems: "center", }} > <View style={{ flex: 1, flexDirection: "column" }}> diff --git a/studentbyer/components/GoBackButton/index.tsx b/studentbyer/components/GoBackButton/index.tsx index b2eba061061c17b6a65a44a3277d3650689ac83c..39d5d4dd0985c58bfec99e4dddfb46e6f4b43f47 100644 --- a/studentbyer/components/GoBackButton/index.tsx +++ b/studentbyer/components/GoBackButton/index.tsx @@ -2,6 +2,9 @@ import * as React from "react"; import { Button } from "react-native-elements"; import Icon from "react-native-vector-icons/FontAwesome5"; +/* + * Button component which makes the app navigate back to the previous screen + */ const GoBackButton = ({ navigation }: any) => { return ( <Button diff --git a/studentbyer/components/Rating/StarRating/index.tsx b/studentbyer/components/Rating/StarRating/index.tsx index 196562b9a3fb71478854f8c081039d2fc8d613c1..1d0b4af9fe2b5b6d4f5b48b6215c396b24646adc 100644 --- a/studentbyer/components/Rating/StarRating/index.tsx +++ b/studentbyer/components/Rating/StarRating/index.tsx @@ -4,10 +4,13 @@ import { View } from "react-native"; type StarType = "FULL" | "HALF" | "EMPTY"; +/* + * Component for displaying a star rating + */ const StarRating = ({ rating, size, - bgcolor + bgcolor, }: { rating: number; size: number; diff --git a/studentbyer/components/Rating/index.tsx b/studentbyer/components/Rating/index.tsx index 86756c9ca342685e8dc1074547c979ac7be3a929..fd669495532d698368fd91b8ce9f7b5a5d283288 100644 --- a/studentbyer/components/Rating/index.tsx +++ b/studentbyer/components/Rating/index.tsx @@ -3,10 +3,13 @@ import { View } from "react-native"; import { Text } from "react-native-elements"; import StarRating from "./StarRating"; +/* + * Component for displaying a star rating for a specific value, for example "Vurdering pris" + */ const Rating = ({ rating, text, - bgcolor + bgcolor, }: { rating: number; text: String; @@ -17,7 +20,7 @@ const Rating = ({ style={{ flex: 5, flexDirection: "row", - justifyContent: "center" + justifyContent: "center", }} > <View @@ -25,7 +28,7 @@ const Rating = ({ flex: 2, flexDirection: "column", paddingLeft: 10, - backgroundColor: bgcolor + backgroundColor: bgcolor, }} > <Text diff --git a/studentbyer/components/SearchParameters/index.tsx b/studentbyer/components/SearchParameters/index.tsx index 320416e16cb1eb6b3206809e7679234a7ae9457d..0b959be3fcc3d14c75a8a828f9e620560e8fe997 100644 --- a/studentbyer/components/SearchParameters/index.tsx +++ b/studentbyer/components/SearchParameters/index.tsx @@ -17,12 +17,12 @@ import debounce from "lodash.debounce"; /* * Component for giving input * Contains searchfield, choicebox for sorting and choicebox for filtering - * Updates state.filterstate.filter in redux on change + * Updates state.filterState.filter in redux on change */ export const SearchParameters = () => { const { filter } = useSelector((state: RootState) => { return { - filter: state.filterState.filter + filter: state.filterState.filter, }; }); @@ -30,7 +30,7 @@ export const SearchParameters = () => { const actions = useActions({ setFilter, setPage }); useEffect(() => { actions.setFilter({ ...filter, sort: "alphabetical" }); - axios.get(`${API}/byer`).then(res => { + axios.get(`${API}/byer`).then((res) => { setCities([...res.data]); }); }, []); @@ -39,13 +39,13 @@ export const SearchParameters = () => { actions.setPage(0); actions.setFilter({ ...filter, - queryString: value + queryString: value, }); }; const debouncedSave = useCallback( //debounce on search - filter is only updated after 0,3 seconds of no writing in searchfield - debounce(nextValue => updateSearch(nextValue), 300), + debounce((nextValue) => updateSearch(nextValue), 300), [] ); @@ -69,7 +69,7 @@ export const SearchParameters = () => { { label: "Alfabetisk A -> Å", value: "alphabetical" }, { label: "Alfabetisk Å -> A", value: "inverseAlphabetical" }, { label: "Total vurdering høy -> lav", value: "ratingHighToLow" }, - { label: "Total vurdering lav -> høy", value: "ratingLowToHigh" } + { label: "Total vurdering lav -> høy", value: "ratingLowToHigh" }, ]; const cityValues = cities.map((city: City) => { return { label: city.navn, value: city.id }; @@ -82,16 +82,16 @@ export const SearchParameters = () => { containerStyle={{ backgroundColor: "#2D3748", borderBottomColor: "transparent", - borderTopColor: "transparent" + borderTopColor: "transparent", }} placeholder="Søk etter studentby..." value={search} - onChangeText={nextValue => handleSearch(nextValue)} + onChangeText={(nextValue) => handleSearch(nextValue)} /> </View> <View style={styles.select}> <RNPickerSelect - onValueChange={value => updateSort(value as Sort)} + onValueChange={(value) => updateSort(value as Sort)} placeholder={sortValues[0]} style={pickerStyle} items={sortValues.slice(1, 4)} @@ -99,7 +99,7 @@ export const SearchParameters = () => { </View> <View style={styles.select}> <RNPickerSelect - onValueChange={value => updateCity(value)} + onValueChange={(value) => updateCity(value)} placeholder={{ label: "Alle byer", value: "" }} style={pickerStyle} items={cityValues} @@ -110,12 +110,12 @@ export const SearchParameters = () => { }; const styles = StyleSheet.create({ container: { - width: "100%" + width: "100%", }, select: { marginVertical: 5, - marginHorizontal: 10 - } + marginHorizontal: 10, + }, }); const pickerStyle = { @@ -124,14 +124,14 @@ const pickerStyle = { paddingTop: 13, paddingHorizontal: 10, paddingBottom: 12, - backgroundColor: "#777777" + backgroundColor: "#777777", }, inputAndroid: { color: "white", - backgroundColor: "#999999" + backgroundColor: "#999999", }, placeholder: { - color: "white" + color: "white", }, - underline: { borderTopWidth: 0 } + underline: { borderTopWidth: 0 }, }; diff --git a/studentbyer/components/StudentCityCards/index.tsx b/studentbyer/components/StudentCityCards/index.tsx index 18c71ad05baa5cb4fce966a90193f0cb58f525a7..e1357cde5d8d90c85dcfa5fe6b3c0db5f8c8a329 100644 --- a/studentbyer/components/StudentCityCards/index.tsx +++ b/studentbyer/components/StudentCityCards/index.tsx @@ -9,12 +9,17 @@ import { OFFSET, API } from "../../constants/AppConstants"; import { StudentCity } from "../../store/studentCity/interfaces"; import axios from "axios"; import { Loader } from "../Loader"; +import { SearchScreenNavigationProp } from "../../screens/SearchScreen"; /* * Component for showing a list of all fetched studentcities * Fetches studentcities on when bottom of list is reached or filter is changed */ -export default function StudentCityCards({ navigation }: any) { +export default function StudentCityCards({ + navigation, +}: { + navigation: SearchScreenNavigationProp; +}) { const { page, filter } = useSelector((state: RootState) => { return { page: state.pageState, @@ -23,23 +28,27 @@ export default function StudentCityCards({ navigation }: any) { }); const [studentCities, setStudentCities] = useState<StudentCity[]>([]); - const [count, setCount] = useState(0); + const [count, setCount] = useState(0); // Total count of StudentCities matching filter in database const [loading, setLoading] = useState(false); const [loadingMore, setLoadingMore] = useState(false); const actions = useActions({ setPage }); + /* This function handles what the component should do when the user has scrolled into the EndReachedThreshold */ const handleLoadMore = () => { - if (loadingMore) return; + if (loadingMore) return; // If we are still trying to fetch StudentCities we should not change the page! if ((page + 1) * OFFSET < count) { + // We should only change the page if there are more StudentCities to fetch actions.setPage(page + 1); } }; + /* Appends the data to the state */ const appendStudentCities = (data: StudentCity[]) => { setStudentCities([...studentCities, ...data]); }; + /* Fetches studentcities using filter and page from Redux, then appends or sets the data using the funct argument */ const loadStudentCities = (funct: (data: StudentCity[]) => void) => { return axios .get(`${API}/studentbyer`, { @@ -63,6 +72,7 @@ export default function StudentCityCards({ navigation }: any) { }); }; + /* Effect for appending on page changes or setting studentcities on filter changes */ useEffect(() => { if (page > 0) { setLoadingMore(true); @@ -73,6 +83,7 @@ export default function StudentCityCards({ navigation }: any) { } }, [page, filter]); + /* Footer component which should be loading if we are trying to fetch more studentcities */ const renderFooter = () => { if (!loadingMore) return null; return <Loader />; diff --git a/studentbyer/constants/AppConstants.ts b/studentbyer/constants/AppConstants.ts index d0e92923ffdb49eeff19b9c03bf8d7d83a63fa7e..cd8901be1c72250908b3538b95fc47c32375c1f6 100644 --- a/studentbyer/constants/AppConstants.ts +++ b/studentbyer/constants/AppConstants.ts @@ -1,2 +1,2 @@ -export const API = "http://it2810-72.idi.ntnu.no:3000/api"; -export const OFFSET = 5; +export const API = "http://it2810-72.idi.ntnu.no:3000/api"; // backend api url +export const OFFSET = 5; // Offset when fetching studentcities diff --git a/studentbyer/constants/Styles.ts b/studentbyer/constants/Styles.ts index f87315b94165e34eaff30df026abb16c8c178d12..61a22d768d00998585602eb202c2be3914d4f4fc 100644 --- a/studentbyer/constants/Styles.ts +++ b/studentbyer/constants/Styles.ts @@ -5,6 +5,12 @@ const globalStyles = StyleSheet.create({ flex: 1, backgroundColor: "#2D3748", }, + container: { + justifyContent: "center", + width: "100%", + height: "100%", + backgroundColor: "#2D3748", + }, }); export default globalStyles; diff --git a/studentbyer/hooks/useActions/index.ts b/studentbyer/hooks/useActions/index.ts index ffd5269ac0e7bf0979e8e0e3c650b096755d7477..6602d56d9b36791de0569ddb2930ba628cf199e5 100644 --- a/studentbyer/hooks/useActions/index.ts +++ b/studentbyer/hooks/useActions/index.ts @@ -3,6 +3,10 @@ import { useStore } from "react-redux"; import { ActionCreatorsMapObject } from "redux"; import { useMemo } from "react"; import { BoundActions } from "./interfaces"; +/* + * Hook used to get actions which can be used on store. Takes in actions (which extends ActionCreatorsMapObject) and returns it as BoundActions. + * BoundActions calls the action creator and immediately dispatches it to the store + */ export const useActions = <M extends ActionCreatorsMapObject>(actions: M) => { const { dispatch, getState } = useStore<RootState>(); const returnKeys = () => @@ -14,7 +18,7 @@ export const useActions = <M extends ActionCreatorsMapObject>(actions: M) => { return typeof action === "function" ? action(dispatch, getState) : dispatch(action); - } + }, }), {} ) as BoundActions<M>; diff --git a/studentbyer/hooks/useCachedResources.ts b/studentbyer/hooks/useCachedResources.ts index 7e7630ab4d6f58435577d508629e2fb799a81fa5..3167eb2129d3adbf556c9d673e621e0152b35604 100644 --- a/studentbyer/hooks/useCachedResources.ts +++ b/studentbyer/hooks/useCachedResources.ts @@ -3,6 +3,7 @@ import * as Font from "expo-font"; import * as SplashScreen from "expo-splash-screen"; import * as React from "react"; +/* Hook for loading all resources needed, came when we initialized with expo init */ export default function useCachedResources() { const [isLoadingComplete, setLoadingComplete] = React.useState(false); @@ -15,7 +16,7 @@ export default function useCachedResources() { // Load fonts await Font.loadAsync({ ...Ionicons.font, - "space-mono": require("../assets/fonts/SpaceMono-Regular.ttf") + "space-mono": require("../assets/fonts/SpaceMono-Regular.ttf"), }); } catch (e) { console.warn(e); diff --git a/studentbyer/screens/AddReviewScreen.tsx b/studentbyer/screens/AddReviewScreen.tsx index 59f0e8a9442a0f71a4506123494df753000b09e4..f8794bc458d85cc2d0a638666f7ad89ffedb576c 100644 --- a/studentbyer/screens/AddReviewScreen.tsx +++ b/studentbyer/screens/AddReviewScreen.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import { StyleSheet } from "react-native"; import { useSelector } from "react-redux"; import { Text, View } from "react-native"; import { RootState } from "../store/store"; @@ -16,16 +15,29 @@ import globalStyles from "../constants/Styles"; import GoBackButton from "../components/GoBackButton"; import { fetchStudentCity } from "../store/studentCity/actions"; import { Loader } from "../components/Loader"; +import { StackNavigationProp } from "@react-navigation/stack"; +import { StackParamList } from "../App"; -const AddReviewScreen = ({ navigation }: any) => { - //const { studentCity } = route.params; +type AddReviewScreenNavigationProp = StackNavigationProp< + StackParamList, + "AddReview" +>; + +/* + * AddReviewScreen for adding reviews to a studentcity + */ +const AddReviewScreen = ({ + navigation, +}: { + navigation: AddReviewScreenNavigationProp; +}) => { const { remoteData } = useSelector((state: RootState) => { return { - remoteData: state.studentCityState.studentCity + remoteData: state.studentCityState.studentCity, }; }); - const studentCity = remoteData.phase == "SUCCESS" ? remoteData.data : null; + const studentCity = remoteData.phase == "SUCCESS" ? remoteData.data : null; // Get the current studentcity const actions = useActions({ setPage, fetchStudentCity }); @@ -35,8 +47,10 @@ const AddReviewScreen = ({ navigation }: any) => { const [vurderingTilstand, setVurderingTilstand] = useState(0); const [error, setError] = useState(""); + /* Handles submit of a review */ const submit = () => { if ( + // All numbers should be set vurderingLokasjon == 0 || vurderingFellesAreal == 0 || vurderingTilstand == 0 || @@ -51,15 +65,15 @@ const AddReviewScreen = ({ navigation }: any) => { vurderingFellesAreal, vurderingTilstand, vurderingPris, - studentby: studentCity.id + studentby: studentCity.id, }) - .then(response => { + .then(() => { actions.fetchStudentCity(studentCity.id); - actions.setPage(0); + actions.setPage(0); // Needed to reload the studentcities-list so that the data there is also up to date navigation.goBack(); showSuccessToast(); }) - .catch(err => showErrorToast(err)); + .catch((err) => showErrorToast(err)); } }; const showSuccessToast = () => { @@ -72,14 +86,14 @@ const AddReviewScreen = ({ navigation }: any) => { if (studentCity) { return ( <SafeAreaView style={globalStyles.statusBar}> - <View style={styles.container}> + <View style={globalStyles.container}> <View style={{ flex: 1, flexDirection: "column" }}> <View style={{ flex: 2, alignItems: "center", flexDirection: "row", - justifyContent: "flex-start" + justifyContent: "flex-start", }} > <GoBackButton navigation={navigation} /> @@ -89,13 +103,13 @@ const AddReviewScreen = ({ navigation }: any) => { flex: 1, flexDirection: "column", justifyContent: "center", - alignItems: "center" + alignItems: "center", }} > <View style={{ flex: 1, - flexDirection: "row" + flexDirection: "row", }} > <Text @@ -109,7 +123,7 @@ const AddReviewScreen = ({ navigation }: any) => { style={{ flex: 8, flexDirection: "column", - alignItems: "center" + alignItems: "center", }} > <AddRating @@ -139,7 +153,7 @@ const AddReviewScreen = ({ navigation }: any) => { flexDirection: "column", justifyContent: "center", alignItems: "center", - paddingTop: 40 + paddingTop: 40, }} > <View style={{ flex: 1, flexDirection: "row" }}> @@ -163,29 +177,11 @@ const AddReviewScreen = ({ navigation }: any) => { ); } else { return ( - <View style={styles.container}> + <View style={globalStyles.container}> <Loader /> </View> ); } }; -const styles = StyleSheet.create({ - container: { - justifyContent: "center", - width: "100%", - height: "100%", - backgroundColor: "#2D3748" - }, - title: { - fontSize: 20, - fontWeight: "bold" - }, - separator: { - marginVertical: 30, - height: 1, - width: "80%" - } -}); - export default AddReviewScreen; diff --git a/studentbyer/screens/HomeScreen.tsx b/studentbyer/screens/HomeScreen.tsx index 32bff5d86e5ccec126afd8f3ea8d04c6dbe68d68..316b91c247454df7aae9045c49cf91eb6964823b 100644 --- a/studentbyer/screens/HomeScreen.tsx +++ b/studentbyer/screens/HomeScreen.tsx @@ -1,12 +1,25 @@ import * as React from "react"; -import { StyleSheet } from "react-native"; import { Text, View } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; import globalStyles from "../constants/Styles"; import Icon from "react-native-vector-icons/FontAwesome5"; import { Button } from "react-native-elements"; +import { StackNavigationProp } from "@react-navigation/stack"; +import { StackParamList } from "../App"; -export const HomeScreen = ({ navigation }: any) => { +export type HomeScreenNavigationProp = StackNavigationProp< + StackParamList, + "Home" +>; + +/* + * Screen which introduces the user to the application + */ +export const HomeScreen = ({ + navigation, +}: { + navigation: HomeScreenNavigationProp; +}) => { return ( <> <SafeAreaView style={globalStyles.statusBar}> @@ -15,7 +28,7 @@ export const HomeScreen = ({ navigation }: any) => { flex: 4, justifyContent: "center", flexDirection: "row", - alignItems: "flex-end" + alignItems: "flex-end", }} > <Icon name="home" solid color="#4FD1C5" size={200} /> @@ -24,7 +37,7 @@ export const HomeScreen = ({ navigation }: any) => { style={{ flex: 1, justifyContent: "center", - flexDirection: "row" + flexDirection: "row", }} > <Text @@ -32,7 +45,7 @@ export const HomeScreen = ({ navigation }: any) => { color: "#4FD1C5", fontSize: 40, fontWeight: "bold", - fontFamily: "space-mono" + fontFamily: "space-mono", }} > STUDENTBOLIGER @@ -42,7 +55,7 @@ export const HomeScreen = ({ navigation }: any) => { style={{ flex: 2, flexDirection: "row", - paddingHorizontal: 10 + paddingHorizontal: 10, }} > <Text style={{ textAlign: "center", fontSize: 18, color: "white" }}> @@ -68,12 +81,3 @@ export const HomeScreen = ({ navigation }: any) => { </> ); }; - -const styles = StyleSheet.create({ - cards: { - flex: 3, - flexDirection: "column", - width: "100%", - backgroundColor: "#2D3748" - } -}); diff --git a/studentbyer/screens/SearchScreen.tsx b/studentbyer/screens/SearchScreen.tsx index 49f85d6854d730363b78ee9d9291bec7d888b2ec..ed8b51a70de3a3858896a1158e21c8b4ab049ae9 100644 --- a/studentbyer/screens/SearchScreen.tsx +++ b/studentbyer/screens/SearchScreen.tsx @@ -1,13 +1,26 @@ import * as React from "react"; import { StyleSheet } from "react-native"; - import StudentCityCards from "../components/StudentCityCards"; import { View } from "react-native"; import { SearchParameters } from "../components/SearchParameters"; import { SafeAreaView } from "react-native-safe-area-context"; import globalStyles from "../constants/Styles"; +import { StackNavigationProp } from "@react-navigation/stack"; +import { StackParamList } from "../App"; + +export type SearchScreenNavigationProp = StackNavigationProp< + StackParamList, + "Search" +>; -export const SearchScreen = ({ navigation }: any) => { +/* + * Screen for searching and scrolling in studentcities + */ +export const SearchScreen = ({ + navigation, +}: { + navigation: SearchScreenNavigationProp; +}) => { return ( <> <SafeAreaView style={globalStyles.statusBar}> @@ -25,6 +38,6 @@ const styles = StyleSheet.create({ flex: 3, flexDirection: "column", width: "100%", - backgroundColor: "#2D3748" - } + backgroundColor: "#2D3748", + }, }); diff --git a/studentbyer/screens/StudentCityScreen.tsx b/studentbyer/screens/StudentCityScreen.tsx index a77c6aa15ece095137991b4b2521df2e8d336a28..e69de21bd9b5799baf0de0adb085e84b96cb455c 100644 --- a/studentbyer/screens/StudentCityScreen.tsx +++ b/studentbyer/screens/StudentCityScreen.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import { StyleSheet } from "react-native"; import { useSelector } from "react-redux"; import { Text, View } from "react-native"; import { RootState } from "../store/store"; @@ -9,11 +8,25 @@ import { SafeAreaView } from "react-native-safe-area-context"; import globalStyles from "../constants/Styles"; import GoBackButton from "../components/GoBackButton"; import { Loader } from "../components/Loader"; +import { StackNavigationProp } from "@react-navigation/stack"; +import { StackParamList } from "../App"; -const StudentCityScreen = ({ navigation }: any) => { +type StudentCityScreenNavigationProp = StackNavigationProp< + StackParamList, + "StudentCity" +>; + +/* + * Screen for displaying details about the student city + */ +const StudentCityScreen = ({ + navigation, +}: { + navigation: StudentCityScreenNavigationProp; +}) => { const { remoteData } = useSelector((state: RootState) => { return { - remoteData: state.studentCityState.studentCity + remoteData: state.studentCityState.studentCity, }; }); @@ -21,7 +34,7 @@ const StudentCityScreen = ({ navigation }: any) => { if (!studentCity) return ( - <View style={styles.container}> + <View style={globalStyles.container}> <Loader /> </View> ); @@ -31,18 +44,19 @@ const StudentCityScreen = ({ navigation }: any) => { [studentCity.vurderingPris, "pris"], [studentCity.vurderingFellesAreal, "fellesareal"], [studentCity.vurderingLokasjon, "lokasjon"], - [studentCity.vurderingTilstand, "tilstand"] + [studentCity.vurderingTilstand, "tilstand"], ]; + return ( <SafeAreaView style={globalStyles.statusBar}> - <View style={styles.container}> + <View style={globalStyles.container}> <View style={{ flex: 1, flexDirection: "column" }}> <View style={{ flex: 2, alignItems: "center", flexDirection: "row", - justifyContent: "flex-start" + justifyContent: "flex-start", }} > <GoBackButton navigation={navigation} /> @@ -53,7 +67,7 @@ const StudentCityScreen = ({ navigation }: any) => { flexDirection: "column", justifyContent: "center", alignItems: "center", - paddingBottom: 40 + paddingBottom: 40, }} > <View style={{ flex: 1, flexDirection: "row" }}> @@ -83,10 +97,10 @@ const StudentCityScreen = ({ navigation }: any) => { style={{ flex: 4, flexDirection: "column", - alignItems: "center" + alignItems: "center", }} > - {ratings.map(val => { + {ratings.map((val) => { return ( <Rating bgcolor="transaprent" @@ -103,7 +117,7 @@ const StudentCityScreen = ({ navigation }: any) => { flexDirection: "column", justifyContent: "center", alignItems: "center", - paddingBottom: 40 + paddingBottom: 40, }} > <View style={{ flex: 1, flexDirection: "row" }}> @@ -124,22 +138,4 @@ const StudentCityScreen = ({ navigation }: any) => { ); }; -const styles = StyleSheet.create({ - container: { - justifyContent: "center", - width: "100%", - height: "100%", - backgroundColor: "#2D3748" - }, - title: { - fontSize: 20, - fontWeight: "bold" - }, - separator: { - marginVertical: 30, - height: 1, - width: "80%" - } -}); - export default StudentCityScreen; diff --git a/studentbyer/store/sagas/studentCitySaga.ts b/studentbyer/store/sagas/studentCitySaga.ts index 69a3d4d8f2362151d583d583b8c222423544bdd8..8a40d7b571149946fbd91ef86d42f8b218001e48 100644 --- a/studentbyer/store/sagas/studentCitySaga.ts +++ b/studentbyer/store/sagas/studentCitySaga.ts @@ -1,11 +1,11 @@ -import { API, OFFSET } from "../../constants/AppConstants"; +import { API } from "../../constants/AppConstants"; import axios from "axios"; -import { call, put, select } from "@redux-saga/core/effects"; +import { call, put } from "@redux-saga/core/effects"; import { RootState } from "../store"; import { pendingStudentCity, setStudentCity, - failureStudentCity + failureStudentCity, } from "../studentCity/actions"; export const getStudentbyIdSelector = (state: RootState) => { diff --git a/studentbyer/store/store.ts b/studentbyer/store/store.ts index 79095c1d4fabaf64839b24288cdee374ed7a7752..c7d48593cd7693a6e8dee9dfa5d9816fcfb19eba 100644 --- a/studentbyer/store/store.ts +++ b/studentbyer/store/store.ts @@ -22,8 +22,9 @@ export default createStore( composeWithDevTools(applyMiddleware(sagaMiddleware)) ); +/* Listens to FETCH_STUDENT_CITY and applies the correct saga */ function* sagas() { yield all([takeLatest(FETCH_STUDENT_CITY, listenToFetchStudentCity)]); } - +// Register the sagas: sagaMiddleware.run(sagas); diff --git a/studentbyer/store/studentCity/reducers.ts b/studentbyer/store/studentCity/reducers.ts index 4366a5a548225cdcc0e165054fdd3309c2986211..433334f3ff03d10e1b4e46045c092268ba048742 100644 --- a/studentbyer/store/studentCity/reducers.ts +++ b/studentbyer/store/studentCity/reducers.ts @@ -2,13 +2,14 @@ import { StudentCityAction, SET_STUDENT_CITY, FAILURE_STUDENT_CITY, - PENDING_STUDENT_CITY + PENDING_STUDENT_CITY, } from "./actionTypes"; import { StudentCityState } from "./interfaces"; const INITIAL_STUDENT_CITIES_STATE: StudentCityState = { - studentCity: { phase: "NOT_ASKED" } + studentCity: { phase: "NOT_ASKED" }, }; + export function studentCityReducer( state = INITIAL_STUDENT_CITIES_STATE, action: StudentCityAction @@ -19,22 +20,22 @@ export function studentCityReducer( ...state, studentCity: { phase: "SUCCESS", - data: action.studentCity - } + data: action.studentCity, + }, }; } case FAILURE_STUDENT_CITY: { return { ...state, - studentCity: { phase: "FAILURE", error: null } + studentCity: { phase: "FAILURE", error: null }, }; } case PENDING_STUDENT_CITY: { return { ...state, studentCity: { - phase: "PENDING" - } + phase: "PENDING", + }, }; } default: