-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
style: enhanced user experience by showing what's happening (#2)
- Loading branch information
Showing
7 changed files
with
391 additions
and
322 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,46 @@ | ||
import {useContext, useEffect} from "react"; | ||
import AuthContext, {Authed} from "../../auth"; | ||
import {useAtom} from "jotai"; | ||
import {feedAtom, getAnnouncements, getRSSFeed, sortFeeds} from "../../stores/feed"; | ||
import {Card} from "react-native-paper"; | ||
import { useContext, useEffect } from "react"; | ||
import AuthContext, { Authed } from "../../auth"; | ||
import { useAtom } from "jotai"; | ||
import { | ||
feedAtom, | ||
getAnnouncements, | ||
getRSSFeed, | ||
sortFeeds, | ||
} from "../../stores/feed"; | ||
import { ActivityIndicator, Card } from "react-native-paper"; | ||
import Item from "./item"; | ||
|
||
export default function Feed() { | ||
const authState = useContext(AuthContext) | ||
const [feed, setFeed] = useAtom(feedAtom) | ||
const authState = useContext(AuthContext); | ||
const [feed, setFeed] = useAtom(feedAtom); | ||
|
||
useEffect(() => { | ||
async function getFeeds() { | ||
if (authState.authenticated === Authed.AUTHENTICATED) { | ||
const feeds = await Promise.all([getRSSFeed(), getAnnouncements(await authState.token)]) | ||
setFeed(sortFeeds(...feeds)) | ||
} | ||
if (authState.authenticated === Authed.GUEST) { | ||
setFeed(await getRSSFeed()) | ||
} | ||
} | ||
useEffect(() => { | ||
async function getFeeds() { | ||
if (authState.authenticated === Authed.AUTHENTICATED) { | ||
const feeds = await Promise.all([ | ||
getRSSFeed(), | ||
getAnnouncements(await authState.token), | ||
]); | ||
setFeed(sortFeeds(...feeds)); | ||
} | ||
if (authState.authenticated === Authed.GUEST) { | ||
setFeed(await getRSSFeed()); | ||
} | ||
} | ||
|
||
getFeeds().then() | ||
}, [authState]) | ||
getFeeds().then(); | ||
}, [authState]); | ||
|
||
return ( | ||
<Card> | ||
<Card.Title title={"Nieuws"} /> | ||
<Card.Content style={{ gap: 10 }}> | ||
{feed.map((item, index) => ( | ||
<Item | ||
key={index} | ||
item={item} | ||
/> | ||
))} | ||
</Card.Content> | ||
</Card> | ||
) | ||
return ( | ||
<Card> | ||
<Card.Title title={"Nieuws"} /> | ||
<Card.Content style={{ gap: 10 }}> | ||
{feed ? ( | ||
feed.map((item, index) => <Item key={index} item={item} />) | ||
) : ( | ||
<ActivityIndicator animating={true} /> | ||
)} | ||
</Card.Content> | ||
</Card> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,73 @@ | ||
import {useContext, useEffect} from "react"; | ||
import AuthContext, {Authed} from "../../auth"; | ||
import {useAtom} from "jotai"; | ||
import {getSlots, Slot, slotsAtom} from "../../stores/register"; | ||
import {Avatar, Card, IconButton} from "react-native-paper"; | ||
import {StyleSheet, TouchableOpacity} from "react-native"; | ||
import {useNavigation} from "@react-navigation/native"; | ||
import {NativeStackNavigationProp} from "react-native-screens/native-stack"; | ||
import {StackParamList} from "../../../App"; | ||
|
||
type SlotNavigationProps = NativeStackNavigationProp<StackParamList> | ||
|
||
function SlotListing({ slot, index }: { slot: Slot, index: number }) { | ||
const navigation = useNavigation<SlotNavigationProps>() | ||
|
||
return ( | ||
<TouchableOpacity onPress={() => navigation.navigate('Slot', { slot: index, title: slot.description })}> | ||
<Card mode={"contained"}> | ||
<Card.Title | ||
title={slot.description} | ||
subtitle={`Er zijn ${slot.available} plaatsen beschikbaar`} | ||
left={(props) => <Avatar.Icon {...props} icon={"calendar-edit"} />} | ||
right={(props) => <IconButton {...props} icon={"chevron-right"} />} | ||
/> | ||
</Card> | ||
</TouchableOpacity> | ||
) | ||
import { useContext, useEffect } from "react"; | ||
import AuthContext, { Authed } from "../../auth"; | ||
import { useAtom } from "jotai"; | ||
import { getSlots, Slot, slotsAtom } from "../../stores/register"; | ||
import { | ||
ActivityIndicator, | ||
Avatar, | ||
Card, | ||
IconButton, | ||
} from "react-native-paper"; | ||
import { StyleSheet, TouchableOpacity } from "react-native"; | ||
import { useNavigation } from "@react-navigation/native"; | ||
import { NativeStackNavigationProp } from "react-native-screens/native-stack"; | ||
import { StackParamList } from "../../../App"; | ||
|
||
type SlotNavigationProps = NativeStackNavigationProp<StackParamList>; | ||
|
||
function SlotListing({ slot, index }: { slot: Slot; index: number }) { | ||
const navigation = useNavigation<SlotNavigationProps>(); | ||
|
||
return ( | ||
<TouchableOpacity | ||
onPress={() => | ||
navigation.navigate("Slot", { slot: index, title: slot.description }) | ||
} | ||
> | ||
<Card mode={"contained"}> | ||
<Card.Title | ||
title={slot.description} | ||
subtitle={`Er zijn ${slot.available} plaatsen beschikbaar`} | ||
left={(props) => <Avatar.Icon {...props} icon={"calendar-edit"} />} | ||
right={(props) => <IconButton {...props} icon={"chevron-right"} />} | ||
/> | ||
</Card> | ||
</TouchableOpacity> | ||
); | ||
} | ||
|
||
export default function Listing() { | ||
const authState = useContext(AuthContext) | ||
const [slots, setSlots] = useAtom(slotsAtom) | ||
|
||
useEffect(() => { | ||
async function fetchDays() { | ||
if (authState.authenticated !== Authed.AUTHENTICATED) return | ||
|
||
setSlots(await getSlots(await authState.token)) | ||
} | ||
|
||
fetchDays().then() | ||
}, [authState]) | ||
|
||
return ( | ||
<Card> | ||
<Card.Title title={"Aanmelden"} /> | ||
<Card.Content style={styles.content}> | ||
{slots.map((slot, index) => ( | ||
<SlotListing key={index} slot={slot} index={index} /> | ||
))} | ||
</Card.Content> | ||
</Card> | ||
) | ||
const authState = useContext(AuthContext); | ||
const [slots, setSlots] = useAtom(slotsAtom); | ||
|
||
useEffect(() => { | ||
async function fetchDays() { | ||
if (authState.authenticated !== Authed.AUTHENTICATED) return; | ||
|
||
setSlots(await getSlots(await authState.token)); | ||
} | ||
|
||
fetchDays().then(); | ||
}, [authState]); | ||
|
||
return ( | ||
<Card> | ||
<Card.Title title={"Aanmelden"} /> | ||
<Card.Content style={styles.content}> | ||
{slots ? ( | ||
slots.map((slot, index) => ( | ||
<SlotListing key={index} slot={slot} index={index} /> | ||
)) | ||
) : ( | ||
<ActivityIndicator animating={true} /> | ||
)} | ||
</Card.Content> | ||
</Card> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
content: { | ||
gap: 10 | ||
} | ||
}) | ||
content: { | ||
gap: 10, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,82 @@ | ||
import {Appbar, Text, useTheme} from "react-native-paper"; | ||
import {RefreshControl, ScrollView, StyleSheet, View} from "react-native"; | ||
import { Appbar, Text, useTheme } from "react-native-paper"; | ||
import { RefreshControl, ScrollView, StyleSheet, View } from "react-native"; | ||
import Listing from "../../components/register/listing"; | ||
import Feed from "../../components/feed/feed"; | ||
import {useContext, useState} from "react"; | ||
import {useAtom} from "jotai"; | ||
import {feedAtom, getAnnouncements, getRSSFeed, sortFeeds} from "../../stores/feed"; | ||
import {getSlots, slotsAtom} from "../../stores/register"; | ||
import AuthContext, {Authed} from "../../auth"; | ||
import {NativeStackNavigationProp} from "react-native-screens/native-stack"; | ||
import {StackParamList} from "../../../App"; | ||
import {useNavigation} from "@react-navigation/native"; | ||
import { useContext, useState } from "react"; | ||
import { useAtom } from "jotai"; | ||
import { | ||
feedAtom, | ||
getAnnouncements, | ||
getRSSFeed, | ||
sortFeeds, | ||
} from "../../stores/feed"; | ||
import { getSlots, slotsAtom } from "../../stores/register"; | ||
import AuthContext, { Authed } from "../../auth"; | ||
import { NativeStackNavigationProp } from "react-native-screens/native-stack"; | ||
import { StackParamList } from "../../../App"; | ||
import { useNavigation } from "@react-navigation/native"; | ||
|
||
type NavigationProps = NativeStackNavigationProp<StackParamList, "Search"> | ||
type NavigationProps = NativeStackNavigationProp<StackParamList, "Search">; | ||
|
||
export default function FeedScreen() { | ||
const navigation = useNavigation<NavigationProps>() | ||
const [refreshing, setRefreshing] = useState(false) | ||
const navigation = useNavigation<NavigationProps>(); | ||
const [refreshing, setRefreshing] = useState(false); | ||
|
||
const authState = useContext(AuthContext) | ||
const [_feed, setFeed] = useAtom(feedAtom) | ||
const [_slots, setSlots] = useAtom(slotsAtom) | ||
const authState = useContext(AuthContext); | ||
const [_feed, setFeed] = useAtom(feedAtom); | ||
const [_slots, setSlots] = useAtom(slotsAtom); | ||
|
||
async function refresh() { | ||
if (authState.authenticated !== Authed.AUTHENTICATED) return | ||
async function refresh() { | ||
if (authState.authenticated !== Authed.AUTHENTICATED) return; | ||
|
||
setRefreshing(true) | ||
const token = await authState.token | ||
await Promise.all([ | ||
new Promise<void>(async resolve => { | ||
const slots = await getSlots(token) | ||
setSlots(slots) | ||
resolve() | ||
}), | ||
new Promise<void>(async resolve => { | ||
const feeds = await Promise.all([ | ||
getRSSFeed(), | ||
getAnnouncements(token) | ||
]) | ||
setFeed(sortFeeds(...feeds)) | ||
resolve() | ||
}) | ||
]) | ||
setRefreshing(false) | ||
} | ||
setRefreshing(true); | ||
const token = await authState.token; | ||
await Promise.all([ | ||
new Promise<void>(async (resolve) => { | ||
setSlots(null); | ||
const slots = await getSlots(token); | ||
setSlots(slots); | ||
resolve(); | ||
}), | ||
new Promise<void>(async (resolve) => { | ||
setFeed(null); | ||
const feeds = await Promise.all([ | ||
getRSSFeed(), | ||
getAnnouncements(token), | ||
]); | ||
setFeed(sortFeeds(...feeds)); | ||
resolve(); | ||
}), | ||
]); | ||
setRefreshing(false); | ||
} | ||
|
||
return ( | ||
<> | ||
<Appbar.Header> | ||
<Appbar.Content title={"Home"} /> | ||
<Appbar.Action icon={"magnify"} onPress={() => navigation.navigate("Search")} /> | ||
</Appbar.Header> | ||
<ScrollView | ||
refreshControl={ | ||
<RefreshControl refreshing={refreshing} onRefresh={refresh} /> | ||
} | ||
> | ||
<View style={styles.container}> | ||
{authState.authenticated === Authed.AUTHENTICATED && <Listing />} | ||
<Feed /> | ||
</View> | ||
</ScrollView> | ||
</> | ||
) | ||
return ( | ||
<> | ||
<Appbar.Header> | ||
<Appbar.Content title={"Home"} /> | ||
<Appbar.Action | ||
icon={"magnify"} | ||
onPress={() => navigation.navigate("Search")} | ||
/> | ||
</Appbar.Header> | ||
<ScrollView | ||
refreshControl={ | ||
<RefreshControl refreshing={refreshing} onRefresh={refresh} /> | ||
} | ||
> | ||
<View style={styles.container}> | ||
{authState.authenticated === Authed.AUTHENTICATED && <Listing />} | ||
<Feed /> | ||
</View> | ||
</ScrollView> | ||
</> | ||
); | ||
} | ||
|
||
const styles = StyleSheet.create({ | ||
container: { | ||
padding: 10, | ||
gap: 10 | ||
} | ||
}) | ||
container: { | ||
padding: 10, | ||
gap: 10, | ||
}, | ||
}); |
Oops, something went wrong.