Skip to content

Commit

Permalink
style: enhanced user experience by showing what's happening (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
sverben authored Apr 24, 2024
1 parent fe70e25 commit 11506f1
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 322 deletions.
71 changes: 39 additions & 32 deletions src/components/feed/feed.tsx
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>
);
}
121 changes: 67 additions & 54 deletions src/components/register/listing.tsx
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,
},
});
130 changes: 70 additions & 60 deletions src/screens/feed/feed.tsx
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,
},
});
Loading

0 comments on commit 11506f1

Please sign in to comment.